diff -Nru ceph-16.2.5/ceph.spec ceph-16.2.6/ceph.spec --- ceph-16.2.5/ceph.spec 2021-07-08 14:06:43.000000000 +0000 +++ ceph-16.2.6/ceph.spec 2021-09-16 14:29:55.000000000 +0000 @@ -49,6 +49,8 @@ %bcond_without lttng %bcond_without libradosstriper %bcond_without ocf +%global luarocks_package_name luarocks +%bcond_without lua_packages %global _remote_tarball_prefix https://download.ceph.com/tarballs/ %endif %if 0%{?suse_version} @@ -73,6 +75,21 @@ %if ! %{defined _fillupdir} %global _fillupdir /var/adm/fillup-templates %endif +#luarocks +%if 0%{?is_opensuse} +# openSUSE +%bcond_without lua_packages +%if 0%{?sle_version} +# openSUSE Leap +%global luarocks_package_name lua53-luarocks +%else +# openSUSE Tumbleweed +%global luarocks_package_name lua54-luarocks +%endif +%else +# SLE +%bcond_with lua_packages +%endif %endif %bcond_with seastar %bcond_with jaeger @@ -96,19 +113,6 @@ %endif %endif -%if 0%{?suse_version} -%if !0%{?is_opensuse} -# SLE does not support luarocks -%bcond_with lua_packages -%else -%global luarocks_package_name lua53-luarocks -%bcond_without lua_packages -%endif -%else -%global luarocks_package_name luarocks -%bcond_without lua_packages -%endif - %{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d} %{!?tmpfiles_create: %global tmpfiles_create systemd-tmpfiles --create} %{!?python3_pkgversion: %global python3_pkgversion 3} @@ -122,7 +126,7 @@ # main package definition ################################################################################# Name: ceph -Version: 16.2.5 +Version: 16.2.6 Release: 0%{?dist} %if 0%{?fedora} || 0%{?rhel} Epoch: 2 @@ -138,7 +142,7 @@ Group: System/Filesystems %endif URL: http://ceph.com/ -Source0: %{?_remote_tarball_prefix}ceph-16.2.5.tar.bz2 +Source0: %{?_remote_tarball_prefix}ceph-16.2.6.tar.bz2 %if 0%{?suse_version} # _insert_obs_source_lines_here ExclusiveArch: x86_64 aarch64 ppc64le s390x @@ -168,7 +172,6 @@ %else BuildRequires: gcc-c++ %endif -BuildRequires: gdbm %if 0%{with tcmalloc} # libprofiler did not build on ppc64le until 2.7.90 %if 0%{?fedora} || 0%{?rhel} >= 8 @@ -292,7 +295,6 @@ BuildRequires: mozilla-nss-devel BuildRequires: keyutils-devel BuildRequires: libopenssl-devel -BuildRequires: lsb-release BuildRequires: openldap2-devel #BuildRequires: krb5 #BuildRequires: krb5-devel @@ -317,7 +319,6 @@ #BuildRequires: krb5-devel BuildRequires: openssl-devel BuildRequires: CUnit-devel -BuildRequires: redhat-lsb-core BuildRequires: python%{python3_pkgversion}-devel BuildRequires: python%{python3_pkgversion}-setuptools BuildRequires: python%{python3_pkgversion}-Cython @@ -329,6 +330,7 @@ %if 0%{with make_check} %if 0%{?fedora} || 0%{?rhel} BuildRequires: golang-github-prometheus +BuildRequires: jsonnet BuildRequires: libtool-ltdl-devel BuildRequires: xmlsec1 BuildRequires: xmlsec1-devel @@ -346,6 +348,7 @@ %endif %if 0%{?suse_version} BuildRequires: golang-github-prometheus-prometheus +BuildRequires: jsonnet BuildRequires: libxmlsec1-1 BuildRequires: libxmlsec1-nss1 BuildRequires: libxmlsec1-openssl1 @@ -1205,7 +1208,7 @@ # common ################################################################################# %prep -%autosetup -p1 -n ceph-16.2.5 +%autosetup -p1 -n ceph-16.2.6 %build # LTO can be enabled as soon as the following GCC bug is fixed: @@ -1335,6 +1338,9 @@ -DWITH_SYSTEM_PMDK:BOOL=ON \ %endif -DBOOST_J=$CEPH_SMP_NCPUS \ +%if 0%{?rhel} + -DWITH_FMT_HEADER_ONLY:BOOL=ON \ +%endif -DWITH_GRAFANA=ON %if %{with cmake_verbose_logging} @@ -1990,9 +1996,8 @@ %endif %postun immutable-object-cache -test -n "$FIRST_ARG" || FIRST_ARG=$1 %systemd_postun ceph-immutable-object-cache@\*.service ceph-immutable-object-cache.target -if [ $FIRST_ARG -ge 1 ] ; then +if [ $1 -ge 1 ] ; then # Restart on upgrade, but only if "CEPH_AUTO_RESTART_ON_UPGRADE" is set to # "yes". In any case: if units are not running, do not touch them. SYSCONF_CEPH=%{_sysconfdir}/sysconfig/ceph diff -Nru ceph-16.2.5/ceph.spec.in ceph-16.2.6/ceph.spec.in --- ceph-16.2.5/ceph.spec.in 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/ceph.spec.in 2021-09-16 14:27:19.000000000 +0000 @@ -49,6 +49,8 @@ %bcond_without lttng %bcond_without libradosstriper %bcond_without ocf +%global luarocks_package_name luarocks +%bcond_without lua_packages %global _remote_tarball_prefix https://download.ceph.com/tarballs/ %endif %if 0%{?suse_version} @@ -73,6 +75,21 @@ %if ! %{defined _fillupdir} %global _fillupdir /var/adm/fillup-templates %endif +#luarocks +%if 0%{?is_opensuse} +# openSUSE +%bcond_without lua_packages +%if 0%{?sle_version} +# openSUSE Leap +%global luarocks_package_name lua53-luarocks +%else +# openSUSE Tumbleweed +%global luarocks_package_name lua54-luarocks +%endif +%else +# SLE +%bcond_with lua_packages +%endif %endif %bcond_with seastar %bcond_with jaeger @@ -96,19 +113,6 @@ %endif %endif -%if 0%{?suse_version} -%if !0%{?is_opensuse} -# SLE does not support luarocks -%bcond_with lua_packages -%else -%global luarocks_package_name lua53-luarocks -%bcond_without lua_packages -%endif -%else -%global luarocks_package_name luarocks -%bcond_without lua_packages -%endif - %{!?_udevrulesdir: %global _udevrulesdir /lib/udev/rules.d} %{!?tmpfiles_create: %global tmpfiles_create systemd-tmpfiles --create} %{!?python3_pkgversion: %global python3_pkgversion 3} @@ -168,7 +172,6 @@ %else BuildRequires: gcc-c++ %endif -BuildRequires: gdbm %if 0%{with tcmalloc} # libprofiler did not build on ppc64le until 2.7.90 %if 0%{?fedora} || 0%{?rhel} >= 8 @@ -292,7 +295,6 @@ BuildRequires: mozilla-nss-devel BuildRequires: keyutils-devel BuildRequires: libopenssl-devel -BuildRequires: lsb-release BuildRequires: openldap2-devel #BuildRequires: krb5 #BuildRequires: krb5-devel @@ -317,7 +319,6 @@ #BuildRequires: krb5-devel BuildRequires: openssl-devel BuildRequires: CUnit-devel -BuildRequires: redhat-lsb-core BuildRequires: python%{python3_pkgversion}-devel BuildRequires: python%{python3_pkgversion}-setuptools BuildRequires: python%{python3_pkgversion}-Cython @@ -329,6 +330,7 @@ %if 0%{with make_check} %if 0%{?fedora} || 0%{?rhel} BuildRequires: golang-github-prometheus +BuildRequires: jsonnet BuildRequires: libtool-ltdl-devel BuildRequires: xmlsec1 BuildRequires: xmlsec1-devel @@ -346,6 +348,7 @@ %endif %if 0%{?suse_version} BuildRequires: golang-github-prometheus-prometheus +BuildRequires: jsonnet BuildRequires: libxmlsec1-1 BuildRequires: libxmlsec1-nss1 BuildRequires: libxmlsec1-openssl1 @@ -1335,6 +1338,9 @@ -DWITH_SYSTEM_PMDK:BOOL=ON \ %endif -DBOOST_J=$CEPH_SMP_NCPUS \ +%if 0%{?rhel} + -DWITH_FMT_HEADER_ONLY:BOOL=ON \ +%endif -DWITH_GRAFANA=ON %if %{with cmake_verbose_logging} @@ -1990,9 +1996,8 @@ %endif %postun immutable-object-cache -test -n "$FIRST_ARG" || FIRST_ARG=$1 %systemd_postun ceph-immutable-object-cache@\*.service ceph-immutable-object-cache.target -if [ $FIRST_ARG -ge 1 ] ; then +if [ $1 -ge 1 ] ; then # Restart on upgrade, but only if "CEPH_AUTO_RESTART_ON_UPGRADE" is set to # "yes". In any case: if units are not running, do not touch them. SYSCONF_CEPH=%{_sysconfdir}/sysconfig/ceph diff -Nru ceph-16.2.5/cmake/modules/BuildBoost.cmake ceph-16.2.6/cmake/modules/BuildBoost.cmake --- ceph-16.2.5/cmake/modules/BuildBoost.cmake 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/cmake/modules/BuildBoost.cmake 2021-09-16 14:27:19.000000000 +0000 @@ -155,7 +155,7 @@ set(boost_sha256 4eb3b8d442b426dc35346235c8733b5ae35ba431690e38c6a8263dce9fcbb402) string(REPLACE "." "_" boost_version_underscore ${boost_version} ) set(boost_url - https://dl.bintray.com/boostorg/release/${boost_version}/source/boost_${boost_version_underscore}.tar.bz2) + https://boostorg.jfrog.io/artifactory/main/release/${boost_version}/source/boost_${boost_version_underscore}.tar.bz2) if(CMAKE_VERSION VERSION_GREATER 3.7) set(boost_url "${boost_url} http://downloads.sourceforge.net/project/boost/boost/${boost_version}/boost_${boost_version_underscore}.tar.bz2") diff -Nru ceph-16.2.5/cmake/modules/CephChecks.cmake ceph-16.2.6/cmake/modules/CephChecks.cmake --- ceph-16.2.5/cmake/modules/CephChecks.cmake 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/cmake/modules/CephChecks.cmake 2021-09-16 14:27:19.000000000 +0000 @@ -56,7 +56,7 @@ CHECK_INCLUDE_FILES("valgrind/helgrind.h" HAVE_VALGRIND_HELGRIND_H) include(CheckTypeSize) -set(CMAKE_EXTRA_INCLUDE_FILES "linux/types.h") +set(CMAKE_EXTRA_INCLUDE_FILES "linux/types.h" "netinet/in.h") CHECK_TYPE_SIZE(__u8 __U8) CHECK_TYPE_SIZE(__u16 __U16) CHECK_TYPE_SIZE(__u32 __U32) @@ -65,6 +65,7 @@ CHECK_TYPE_SIZE(__s16 __S16) CHECK_TYPE_SIZE(__s32 __S32) CHECK_TYPE_SIZE(__s64 __S64) +CHECK_TYPE_SIZE(in_addr_t IN_ADDR_T) unset(CMAKE_EXTRA_INCLUDE_FILES) include(CheckSymbolExists) diff -Nru ceph-16.2.5/cmake/modules/Findfmt.cmake ceph-16.2.6/cmake/modules/Findfmt.cmake --- ceph-16.2.5/cmake/modules/Findfmt.cmake 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/cmake/modules/Findfmt.cmake 2021-09-16 14:27:19.000000000 +0000 @@ -35,9 +35,27 @@ fmt_VERSION_STRING) if(fmt_FOUND AND NOT (TARGET fmt::fmt)) - add_library(fmt::fmt UNKNOWN IMPORTED) - set_target_properties(fmt::fmt PROPERTIES + add_library(fmt-header-only INTERFACE) + set_target_properties(fmt-header-only PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${fmt_INCLUDE_DIR}" + INTERFACE_COMPILE_DEFINITIONS FMT_HEADER_ONLY=1 + INTERFACE_COMPILE_FEATURES cxx_std_11) + + add_library(fmt UNKNOWN IMPORTED GLOBAL) + set_target_properties(fmt PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${fmt_INCLUDE_DIR}" + INTERFACE_COMPILE_FEATURES cxx_std_11 IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${fmt_LIBRARY}") + + if(WITH_FMT_HEADER_ONLY) + # please note, this is different from how upstream defines fmt::fmt. + # in order to force 3rd party libraries to link against fmt-header-only if + # WITH_FMT_HEADER_ONLY is ON, we have to point fmt::fmt to fmt-header-only + # in this case. + add_library(fmt::fmt ALIAS fmt-header-only) + else() + add_library(fmt::fmt ALIAS fmt) + endif() + endif() diff -Nru ceph-16.2.5/CMakeLists.txt ceph-16.2.6/CMakeLists.txt --- ceph-16.2.5/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -2,7 +2,7 @@ # remove cmake/modules/FindPython* once 3.12 is required project(ceph - VERSION 16.0.0 + VERSION 16.2.6 LANGUAGES CXX C ASM) foreach(policy diff -Nru ceph-16.2.5/debian/changelog ceph-16.2.6/debian/changelog --- ceph-16.2.5/debian/changelog 2021-09-10 13:56:29.000000000 +0000 +++ ceph-16.2.6/debian/changelog 2021-09-18 12:03:53.000000000 +0000 @@ -1,3 +1,10 @@ +ceph (16.2.6-0ubuntu1) impish; urgency=medium + + * New upstream stable release (LP: #1943932). + * d/p/*: Refresh. + + -- James Page Sat, 18 Sep 2021 13:03:53 +0100 + ceph (16.2.5-0ubuntu4) impish; urgency=medium * d/control: The ISA-L EC plugin changed its build dependency from yasm to diff -Nru ceph-16.2.5/debian/patches/32bit-fixes.patch ceph-16.2.6/debian/patches/32bit-fixes.patch --- ceph-16.2.5/debian/patches/32bit-fixes.patch 2021-09-09 07:03:26.000000000 +0000 +++ ceph-16.2.6/debian/patches/32bit-fixes.patch 2021-09-18 12:03:44.000000000 +0000 @@ -4,7 +4,7 @@ --- a/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc +++ b/src/tools/rbd_mirror/image_replayer/snapshot/Replayer.cc -@@ -235,7 +235,8 @@ bool Replayer::get_replay_status(std: +@@ -253,7 +253,8 @@ bool Replayer::get_replay_status(std: json_spirit::mObject root_obj; root_obj["replay_state"] = replay_state; @@ -14,7 +14,7 @@ auto matching_remote_snap_id = util::compute_remote_snap_id( m_state_builder->local_image_ctx->image_lock, -@@ -249,8 +250,8 @@ bool Replayer::get_replay_status(std: +@@ -267,8 +268,8 @@ bool Replayer::get_replay_status(std: // use the timestamp from the matching remote image since // the local snapshot would just be the time the snapshot was // synced and not the consistency point in time. @@ -25,7 +25,7 @@ } matching_remote_snap_it = m_state_builder->remote_image_ctx->snap_info.find( -@@ -258,7 +259,8 @@ bool Replayer::get_replay_status(std: +@@ -276,7 +277,8 @@ bool Replayer::get_replay_status(std: if (m_remote_snap_id_end != CEPH_NOSNAP && matching_remote_snap_it != m_state_builder->remote_image_ctx->snap_info.end()) { @@ -37,7 +37,7 @@ static_cast(std::max(1U, m_local_object_count))); --- a/src/common/buffer.cc +++ b/src/common/buffer.cc -@@ -2268,7 +2268,7 @@ MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::ra +@@ -2272,7 +2272,7 @@ MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::ra void ceph::buffer::list::page_aligned_appender::_refill(size_t len) { const size_t alloc = \ @@ -59,7 +59,7 @@ { --- a/src/os/bluestore/BlueFS.cc +++ b/src/os/bluestore/BlueFS.cc -@@ -3744,11 +3744,11 @@ int BlueFS::do_replay_recovery_read(File +@@ -3787,11 +3787,11 @@ int BlueFS::do_replay_recovery_read(File size_t BlueFS::probe_alloc_avail(int dev, uint64_t alloc_size) { @@ -106,7 +106,7 @@ R::ReadOp op; --- a/src/tools/cephfs_mirror/FSMirror.cc +++ b/src/tools/cephfs_mirror/FSMirror.cc -@@ -334,7 +334,7 @@ void FSMirror::handle_acquire_directory( +@@ -345,7 +345,7 @@ void FSMirror::handle_acquire_directory( std::scoped_lock locker(m_lock); m_directories.emplace(dir_path); m_service_daemon->add_or_update_fs_attribute(m_filesystem.fscid, SERVICE_DAEMON_DIR_COUNT_KEY, @@ -115,7 +115,7 @@ for (auto &[peer, peer_replayer] : m_peer_replayers) { dout(10) << ": peer=" << peer << dendl; -@@ -352,7 +352,7 @@ void FSMirror::handle_release_directory( +@@ -363,7 +363,7 @@ void FSMirror::handle_release_directory( if (it != m_directories.end()) { m_directories.erase(it); m_service_daemon->add_or_update_fs_attribute(m_filesystem.fscid, SERVICE_DAEMON_DIR_COUNT_KEY, diff -Nru ceph-16.2.5/debian/patches/bug1914584.patch ceph-16.2.6/debian/patches/bug1914584.patch --- ceph-16.2.5/debian/patches/bug1914584.patch 2021-09-09 07:03:26.000000000 +0000 +++ ceph-16.2.6/debian/patches/bug1914584.patch 2021-09-18 12:03:44.000000000 +0000 @@ -29,7 +29,7 @@ --- a/src/rgw/rgw_user.cc +++ b/src/rgw/rgw_user.cc -@@ -1955,7 +1955,14 @@ int RGWUser::remove(RGWUserAdminOpState& +@@ -1971,7 +1971,14 @@ int RGWUser::remove(const DoutPrefixProv ret = check_op(op_state, &subprocess_msg); if (ret < 0) { diff -Nru ceph-16.2.5/debian/patches/disable-log-slow-requests.patch ceph-16.2.6/debian/patches/disable-log-slow-requests.patch --- ceph-16.2.5/debian/patches/disable-log-slow-requests.patch 2021-09-09 07:03:26.000000000 +0000 +++ ceph-16.2.6/debian/patches/disable-log-slow-requests.patch 2021-09-18 12:03:44.000000000 +0000 @@ -28,7 +28,7 @@ --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc -@@ -7748,7 +7748,6 @@ vector OSD::get_heal +@@ -7758,7 +7758,6 @@ vector OSD::get_heal << " currently " << op.state_string(); lgeneric_subdout(cct,osd,20) << ss.str() << dendl; diff -Nru ceph-16.2.5/debian/patches/enable-strsignal.patch ceph-16.2.6/debian/patches/enable-strsignal.patch --- ceph-16.2.5/debian/patches/enable-strsignal.patch 2021-09-09 07:03:26.000000000 +0000 +++ ceph-16.2.6/debian/patches/enable-strsignal.patch 2021-09-18 12:03:44.000000000 +0000 @@ -5,7 +5,7 @@ --- a/CMakeLists.txt +++ b/CMakeLists.txt -@@ -500,7 +500,7 @@ if(WITH_THREAD_SAFE_RES_QUERY) +@@ -501,7 +501,7 @@ if(WITH_THREAD_SAFE_RES_QUERY) set(HAVE_THREAD_SAFE_RES_QUERY 1 CACHE INTERNAL "Thread safe res_query supported.") endif() diff -Nru ceph-16.2.5/doc/cephadm/client-setup.rst ceph-16.2.6/doc/cephadm/client-setup.rst --- ceph-16.2.5/doc/cephadm/client-setup.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/client-setup.rst 2021-09-16 14:27:19.000000000 +0000 @@ -1,40 +1,45 @@ ======================= Basic Ceph Client Setup ======================= -Client machines need some basic configuration in order to interact with -a cluster. This document describes how to configure a client machine -for cluster interaction. - -.. note:: Most client machines only need the `ceph-common` package and - its dependencies installed. That will supply the basic `ceph` - and `rados` commands, as well as other commands like - `mount.ceph` and `rbd`. +Client machines require some basic configuration to interact with +Ceph clusters. This section describes how to configure a client machine +so that it can interact with a Ceph cluster. + +.. note:: + Most client machines need to install only the `ceph-common` package + and its dependencies. Such a setup supplies the basic `ceph` and + `rados` commands, as well as other commands including `mount.ceph` + and `rbd`. Config File Setup ================= -Client machines can generally get away with a smaller config file than -a full-fledged cluster member. To generate a minimal config file, log -into a host that is already configured as a client or running a cluster -daemon, and then run - -.. code-block:: bash - - ceph config generate-minimal-conf - -This will generate a minimal config file that will tell the client how to -reach the Ceph Monitors. The contents of this file should typically be -installed in `/etc/ceph/ceph.conf`. +Client machines usually require smaller configuration files (here +sometimes called "config files") than do full-fledged cluster members. +To generate a minimal config file, log into a host that has been +configured as a client or that is running a cluster daemon, and then run the following command: + +.. prompt:: bash # + + ceph config generate-minimal-conf + +This command generates a minimal config file that tells the client how +to reach the Ceph monitors. The contents of this file should usually +be installed in ``/etc/ceph/ceph.conf``. Keyring Setup ============= -Most Ceph clusters are run with authentication enabled, and the client will -need keys in order to communicate with cluster machines. To generate a -keyring file with credentials for `client.fs`, log into an extant cluster -member and run +Most Ceph clusters run with authentication enabled. This means that +the client needs keys in order to communicate with the machines in the +cluster. To generate a keyring file with credentials for `client.fs`, +log into an running cluster member and run the following command: -.. code-block:: bash +.. prompt:: bash $ - ceph auth get-or-create client.fs + ceph auth get-or-create client.fs -The resulting output should be put into a keyring file, typically -`/etc/ceph/ceph.keyring`. +The resulting output is directed into a keyring file, typically +``/etc/ceph/ceph.keyring``. + +To gain a broader understanding of client keyring distribution and administration, you should read :ref:`client_keyrings_and_configs`. + +To see an example that explains how to distribute ``ceph.conf`` configuration files to hosts that are tagged with the ``bare_config`` label, you should read the section called "Distributing ceph.conf to hosts tagged with bare_config" in the section called :ref:`etc_ceph_conf_distribution`. diff -Nru ceph-16.2.5/doc/cephadm/host-management.rst ceph-16.2.6/doc/cephadm/host-management.rst --- ceph-16.2.5/doc/cephadm/host-management.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/host-management.rst 2021-09-16 14:27:19.000000000 +0000 @@ -64,48 +64,47 @@ Removing Hosts ============== -If the node that want you to remove is running OSDs, make sure you remove the OSDs from the node. +A host can safely be removed from a the cluster once all daemons are removed from it. -To remove a host from a cluster, do the following: +To drain all daemons from a host do the following: -For all Ceph service types, except for ``node-exporter`` and ``crash``, remove -the host from the placement specification file (for example, cluster.yml). -For example, if you are removing the host named host2, remove all occurrences of -``- host2`` from all ``placement:`` sections. +.. prompt:: bash # + + ceph orch host drain ** + +The '_no_schedule' label will be applied to the host. See :ref:`cephadm-special-host-labels` -Update: +All osds on the host will be scheduled to be removed. You can check osd removal progress with the following: -.. code-block:: yaml +.. prompt:: bash # - service_type: rgw - placement: - hosts: - - host1 - - host2 + ceph orch osd rm status -To: +see :ref:`cephadm-osd-removal` for more details about osd removal -.. code-block:: yaml +You can check if there are no deamons left on the host with the following: +.. prompt:: bash # - service_type: rgw - placement: - hosts: - - host1 + ceph orch ps -Remove the host from cephadm's environment: +Once all daemons are removed you can remove the host with the following: .. prompt:: bash # - ceph orch host rm host2 + ceph orch host rm +Offline host removal +-------------------- -If the host is running ``node-exporter`` and crash services, remove them by running -the following command on the host: +If a host is offline and can not be recovered it can still be removed from the cluster with the following: .. prompt:: bash # - cephadm rm-daemon --fsid CLUSTER_ID --name SERVICE_NAME + ceph orch host rm --offline --force + +This can potentially cause data loss as osds will be forcefully purged from the cluster by calling ``osd purge-actual`` for each osd. +Service specs that still contain this host should be manually updated. .. _orchestrator-host-labels: diff -Nru ceph-16.2.5/doc/cephadm/install.rst ceph-16.2.6/doc/cephadm/install.rst --- ceph-16.2.5/doc/cephadm/install.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/install.rst 2021-09-16 14:27:19.000000000 +0000 @@ -173,6 +173,11 @@ Also, you can run ``cephadm bootstrap -h`` to see all of ``cephadm``'s available options. +* By default, Ceph daemons send their log output to stdout/stderr, which is picked + up by the container runtime (docker or podman) and (on most systems) sent to + journald. If you want Ceph to write traditional log files to ``/var/log/ceph/$fsid``, + use ``--log-to-file`` option during bootstrap. + * Larger Ceph clusters perform better when (external to the Ceph cluster) public network traffic is separated from (internal to the Ceph cluster) cluster traffic. The internal cluster traffic handles replication, recovery, diff -Nru ceph-16.2.5/doc/cephadm/monitoring.rst ceph-16.2.6/doc/cephadm/monitoring.rst --- ceph-16.2.5/doc/cephadm/monitoring.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/monitoring.rst 2021-09-16 14:27:19.000000000 +0000 @@ -52,12 +52,6 @@ To set up monitoring on a Ceph cluster that has no monitoring, follow the steps below: -#. Enable the Prometheus module in the ceph-mgr daemon. This exposes the internal Ceph metrics so that Prometheus can scrape them: - - .. prompt:: bash # - - ceph mgr module enable prometheus - #. Deploy a node-exporter service on every node of the cluster. The node-exporter provides host-level metrics like CPU and memory utilization: .. prompt:: bash # diff -Nru ceph-16.2.5/doc/cephadm/mon.rst ceph-16.2.6/doc/cephadm/mon.rst --- ceph-16.2.5/doc/cephadm/mon.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/mon.rst 2021-09-16 14:27:19.000000000 +0000 @@ -26,7 +26,11 @@ If all of the ceph monitor daemons in your cluster are in the same subnet, manual administration of the ceph monitor daemons is not necessary. ``cephadm`` will automatically add up to five monitors to the subnet, as -needed, as new hosts are added to the cluster. +needed, as new hosts are added to the cluster. + +By default, cephadm will deploy 5 daemons on arbitrary hosts. See +:ref:`orchestrator-cli-placement-spec` for details of specifying +the placement of daemons. Designating a Particular Subnet for Monitors -------------------------------------------- @@ -48,88 +52,84 @@ Cephadm deploys new monitor daemons only on hosts that have IP addresses in the designated subnet. -Changing the number of monitors from the default ------------------------------------------------- - -If you want to adjust the default of 5 monitors, run this command: +You can also specify two public networks by using a list of networks: .. prompt:: bash # - ceph orch apply mon ** + ceph config set mon public_network *,* -Deploying monitors only to specific hosts ------------------------------------------ - -To deploy monitors on a specific set of hosts, run this command: + For example: .. prompt:: bash # - ceph orch apply mon ** + ceph config set mon public_network 10.1.2.0/24,192.168.0.1/24 - Be sure to include the first (bootstrap) host in this list. -Using Host Labels ------------------ +Deploying Monitors on a Particular Network +------------------------------------------ + +You can explicitly specify the IP address or CIDR network for each monitor and +control where each monitor is placed. To disable automated monitor deployment, +run this command: -You can control which hosts the monitors run on by making use of host labels. -To set the ``mon`` label to the appropriate hosts, run this command: - .. prompt:: bash # - ceph orch host label add ** mon + ceph orch apply mon --unmanaged - To view the current hosts and labels, run this command: + To deploy each additional monitor: .. prompt:: bash # - ceph orch host ls + ceph orch daemon add mon * - For example: + For example, to deploy a second monitor on ``newhost1`` using an IP + address ``10.1.2.123`` and a third monitor on ``newhost2`` in + network ``10.1.2.0/24``, run the following commands: .. prompt:: bash # - ceph orch host label add host1 mon - ceph orch host label add host2 mon - ceph orch host label add host3 mon - ceph orch host ls + ceph orch apply mon --unmanaged + ceph orch daemon add mon newhost1:10.1.2.123 + ceph orch daemon add mon newhost2:10.1.2.0/24 + + Now, enable automatic placement of Daemons + + .. prompt:: bash # - .. code-block:: bash + ceph orch apply mon --placement="newhost1,newhost2,newhost3" --dry-run - HOST ADDR LABELS STATUS - host1 mon - host2 mon - host3 mon - host4 - host5 + See :ref:`orchestrator-cli-placement-spec` for details of specifying + the placement of daemons. - Tell cephadm to deploy monitors based on the label by running this command: + Finally apply this new placement by dropping ``--dry-run`` .. prompt:: bash # - ceph orch apply mon label:mon + ceph orch apply mon --placement="newhost1,newhost2,newhost3" -See also :ref:`host labels `. -Deploying Monitors on a Particular Network ------------------------------------------- +Moving Monitors to a Different Network +-------------------------------------- -You can explicitly specify the IP address or CIDR network for each monitor and -control where each monitor is placed. To disable automated monitor deployment, -run this command: +To move Monitors to a new network, deploy new monitors on the new network and +subsequently remove monitors from the old network. It is not advised to +modify and inject the ``monmap`` manually. + +First, disable the automated placement of daemons: .. prompt:: bash # ceph orch apply mon --unmanaged - To deploy each additional monitor: +To deploy each additional monitor: .. prompt:: bash # - ceph orch daemon add mon * [...]* + ceph orch daemon add mon ** - For example, to deploy a second monitor on ``newhost1`` using an IP - address ``10.1.2.123`` and a third monitor on ``newhost2`` in - network ``10.1.2.0/24``, run the following commands: +For example, to deploy a second monitor on ``newhost1`` using an IP +address ``10.1.2.123`` and a third monitor on ``newhost2`` in +network ``10.1.2.0/24``, run the following commands: .. prompt:: bash # @@ -137,52 +137,35 @@ ceph orch daemon add mon newhost1:10.1.2.123 ceph orch daemon add mon newhost2:10.1.2.0/24 - .. note:: - The **apply** command can be confusing. For this reason, we recommend using - YAML specifications. - - Each ``ceph orch apply mon`` command supersedes the one before it. - This means that you must use the proper comma-separated list-based - syntax when you want to apply monitors to more than one host. - If you do not use the proper syntax, you will clobber your work - as you go. - - For example: - - .. prompt:: bash # - - ceph orch apply mon host1 - ceph orch apply mon host2 - ceph orch apply mon host3 - - This results in only one host having a monitor applied to it: host 3. - - (The first command creates a monitor on host1. Then the second command - clobbers the monitor on host1 and creates a monitor on host2. Then the - third command clobbers the monitor on host2 and creates a monitor on - host3. In this scenario, at this point, there is a monitor ONLY on - host3.) - - To make certain that a monitor is applied to each of these three hosts, - run a command like this: - - .. prompt:: bash # - - ceph orch apply mon "host1,host2,host3" - - There is another way to apply monitors to multiple hosts: a ``yaml`` file - can be used. Instead of using the "ceph orch apply mon" commands, run a - command of this form: - - .. prompt:: bash # - - ceph orch apply -i file.yaml - - Here is a sample **file.yaml** file:: - - service_type: mon - placement: - hosts: - - host1 - - host2 - - host3 + Subsequently remove monitors from the old network: + + .. prompt:: bash # + + ceph orch daemon rm *mon.* + + Update the ``public_network``: + + .. prompt:: bash # + + ceph config set mon public_network ** + + For example: + + .. prompt:: bash # + + ceph config set mon public_network 10.1.2.0/24 + + Now, enable automatic placement of Daemons + + .. prompt:: bash # + + ceph orch apply mon --placement="newhost1,newhost2,newhost3" --dry-run + + See :ref:`orchestrator-cli-placement-spec` for details of specifying + the placement of daemons. + + Finally apply this new placement by dropping ``--dry-run`` + + .. prompt:: bash # + + ceph orch apply mon --placement="newhost1,newhost2,newhost3" diff -Nru ceph-16.2.5/doc/cephadm/operations.rst ceph-16.2.6/doc/cephadm/operations.rst --- ceph-16.2.5/doc/cephadm/operations.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/operations.rst 2021-09-16 14:27:19.000000000 +0000 @@ -2,28 +2,40 @@ Cephadm Operations ================== +.. _watching_cephadm_logs: + Watching cephadm log messages ============================= -Cephadm logs to the ``cephadm`` cluster log channel, meaning you can -monitor progress in realtime with:: +Cephadm writes logs to the ``cephadm`` cluster log channel. You can +monitor Ceph's activity in real time by reading the logs as they fill +up. Run the following command to see the logs in real time: + +.. prompt:: bash # + + ceph -W cephadm + +By default, this command shows info-level events and above. To see +debug-level messages as well as info-level events, run the following +commands: - # ceph -W cephadm +.. prompt:: bash # -By default it will show info-level events and above. To see -debug-level messages too:: + ceph config set mgr mgr/cephadm/log_to_cluster_level debug + ceph -W cephadm --watch-debug - # ceph config set mgr mgr/cephadm/log_to_cluster_level debug - # ceph -W cephadm --watch-debug +.. warning:: -Be careful: the debug messages are very verbose! + The debug messages are very verbose! -You can see recent events with:: +You can see recent events by running the following command: - # ceph log last cephadm +.. prompt:: bash # + + ceph log last cephadm These events are also logged to the ``ceph.cephadm.log`` file on -monitor hosts and to the monitor daemons' stderr. +monitor hosts as well as to the monitor daemons' stderr. .. _cephadm-logs: @@ -31,45 +43,68 @@ Ceph daemon logs ================ -Logging to stdout ------------------ +Logging to journald +------------------- + +Ceph daemons traditionally write logs to ``/var/log/ceph``. Ceph daemons log to +journald by default and Ceph logs are captured by the container runtime +environment. They are accessible via ``journalctl``. + +.. note:: Prior to Quincy, ceph daemons logged to stderr. -Traditionally, Ceph daemons have logged to ``/var/log/ceph``. By -default, cephadm daemons log to stderr and the logs are -captured by the container runtime environment. For most systems, by -default, these logs are sent to journald and accessible via -``journalctl``. +Example of logging to journald +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For example, to view the logs for the daemon ``mon.foo`` for a cluster with ID ``5c5a50ae-272a-455d-99e9-32c6a013e694``, the command would be -something like:: +something like: + +.. prompt:: bash # journalctl -u ceph-5c5a50ae-272a-455d-99e9-32c6a013e694@mon.foo This works well for normal operations when logging levels are low. -To disable logging to stderr:: - - ceph config set global log_to_stderr false - ceph config set global mon_cluster_log_to_stderr false - Logging to files ---------------- -You can also configure Ceph daemons to log to files instead of stderr, -just like they have in the past. When logging to files, Ceph logs appear -in ``/var/log/ceph/``. +You can also configure Ceph daemons to log to files instead of to +journald if you prefer logs to appear in files (as they did in earlier, +pre-cephadm, pre-Octopus versions of Ceph). When Ceph logs to files, +the logs appear in ``/var/log/ceph/``. If you choose to +configure Ceph to log to files instead of to journald, remember to +configure Ceph so that it will not log to journald (the commands for +this are covered below). + +Enabling logging to files +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To enable logging to files, run the following commands: -To enable logging to files:: +.. prompt:: bash # ceph config set global log_to_file true ceph config set global mon_cluster_log_to_file true -We recommend disabling logging to stderr (see above) or else everything -will be logged twice:: +Disabling logging to journald +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you choose to log to files, we recommend disabling logging to journald or else +everything will be logged twice. Run the following commands to disable logging +to stderr: + +.. prompt:: bash # ceph config set global log_to_stderr false ceph config set global mon_cluster_log_to_stderr false + ceph config set global log_to_journald false + ceph config set global mon_cluster_log_to_journald false + +.. note:: You can change the default by passing --log-to-file during + bootstrapping a new cluster. + +Modifying the log retention schedule +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, cephadm sets up log rotation on each host to rotate these files. You can configure the logging retention schedule by modifying @@ -79,12 +114,13 @@ Data location ============= -Cephadm daemon data and logs in slightly different locations than older -versions of ceph: +Cephadm stores daemon data and logs in different locations than did +older, pre-cephadm (pre Octopus) versions of ceph: -* ``/var/log/ceph/`` contains all cluster logs. Note - that by default cephadm logs via stderr and the container runtime, - so these logs are normally not present. +* ``/var/log/ceph/`` contains all cluster logs. By + default, cephadm logs via stderr and the container runtime. These + logs will not exist unless you have enabled logging to files as + described in `cephadm-logs`_. * ``/var/lib/ceph/`` contains all cluster daemon data (besides logs). * ``/var/lib/ceph//`` contains all data for @@ -98,58 +134,69 @@ Disk usage ---------- -Because a few Ceph daemons may store a significant amount of data in -``/var/lib/ceph`` (notably, the monitors and prometheus), we recommend -moving this directory to its own disk, partition, or logical volume so -that it does not fill up the root file system. +Because a few Ceph daemons (notably, the monitors and prometheus) store a +large amount of data in ``/var/lib/ceph`` , we recommend moving this +directory to its own disk, partition, or logical volume so that it does not +fill up the root file system. Health checks ============= -The cephadm module provides additional healthchecks to supplement the default healthchecks -provided by the Cluster. These additional healthchecks fall into two categories; - -- **cephadm operations**: Healthchecks in this category are always executed when the cephadm module is active. -- **cluster configuration**: These healthchecks are *optional*, and focus on the configuration of the hosts in - the cluster +The cephadm module provides additional health checks to supplement the +default health checks provided by the Cluster. These additional health +checks fall into two categories: + +- **cephadm operations**: Health checks in this category are always + executed when the cephadm module is active. +- **cluster configuration**: These health checks are *optional*, and + focus on the configuration of the hosts in the cluster. CEPHADM Operations ------------------ CEPHADM_PAUSED -^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~ + +This indicates that cephadm background work has been paused with +``ceph orch pause``. Cephadm continues to perform passive monitoring +activities (like checking host and daemon status), but it will not +make any changes (like deploying or removing daemons). -Cephadm background work has been paused with ``ceph orch pause``. Cephadm -continues to perform passive monitoring activities (like checking -host and daemon status), but it will not make any changes (like deploying -or removing daemons). +Resume cephadm work by running the following command: -Resume cephadm work with:: +.. prompt:: bash # ceph orch resume .. _cephadm-stray-host: CEPHADM_STRAY_HOST -^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~ + +This indicates that one or more hosts have Ceph daemons that are +running, but are not registered as hosts managed by *cephadm*. This +means that those services cannot currently be managed by cephadm +(e.g., restarted, upgraded, included in `ceph orch ps`). -One or more hosts have running Ceph daemons but are not registered as -hosts managed by *cephadm*. This means that those services cannot -currently be managed by cephadm (e.g., restarted, upgraded, included -in `ceph orch ps`). +You can manage the host(s) by running the following command: -You can manage the host(s) with:: +.. prompt:: bash # ceph orch host add ** -Note that you may need to configure SSH access to the remote host -before this will work. +.. note:: + + You might need to configure SSH access to the remote host + before this will work. Alternatively, you can manually connect to the host and ensure that services on that host are removed or migrated to a host that is managed by *cephadm*. -You can also disable this warning entirely with:: +This warning can be disabled entirely by running the following +command: + +.. prompt:: bash # ceph config set mgr mgr/cephadm/warn_on_stray_hosts false @@ -157,7 +204,7 @@ domain names. CEPHADM_STRAY_DAEMON -^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~ One or more Ceph daemons are running but not are not managed by *cephadm*. This may be because they were deployed using a different @@ -170,12 +217,14 @@ usually easiest to provision a new daemon with the ``ceph orch apply`` command and then stop the unmanaged daemon. -This warning can be disabled entirely with:: +This warning can be disabled entirely by running the following command: + +.. prompt:: bash # ceph config set mgr mgr/cephadm/warn_on_stray_daemons false CEPHADM_HOST_CHECK_FAILED -^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~ One or more hosts have failed the basic cephadm host check, which verifies that (1) the host is reachable and cephadm can be executed there, and (2) @@ -183,58 +232,80 @@ runtime (podman or docker) and working time synchronization. If this test fails, cephadm will no be able to manage services on that host. -You can manually run this check with:: +You can manually run this check by running the following command: + +.. prompt:: bash # ceph cephadm check-host ** -You can remove a broken host from management with:: +You can remove a broken host from management by running the following command: + +.. prompt:: bash # ceph orch host rm ** -You can disable this health warning with:: +You can disable this health warning by running the following command: + +.. prompt:: bash # ceph config set mgr mgr/cephadm/warn_on_failed_host_check false Cluster Configuration Checks ---------------------------- -Cephadm periodically scans each of the hosts in the cluster, to understand the state -of the OS, disks, NICs etc. These facts can then be analysed for consistency across the hosts -in the cluster to identify any configuration anomalies. +Cephadm periodically scans each of the hosts in the cluster in order +to understand the state of the OS, disks, NICs etc. These facts can +then be analysed for consistency across the hosts in the cluster to +identify any configuration anomalies. + +Enabling Cluster Configuration Checks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The configuration checks are an **optional** feature, enabled by the following command -:: +The configuration checks are an **optional** feature, and are enabled +by running the following command: + +.. prompt:: bash # ceph config set mgr mgr/cephadm/config_checks_enabled true -The configuration checks are triggered after each host scan (1m). The cephadm log entries will -show the current state and outcome of the configuration checks as follows; +States Returned by Cluster Configuration Checks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The configuration checks are triggered after each host scan (1m). The +cephadm log entries will show the current state and outcome of the +configuration checks as follows: -Disabled state (config_checks_enabled false) -:: +Disabled state (config_checks_enabled false): + +.. code-block:: bash ALL cephadm checks are disabled, use 'ceph config set mgr mgr/cephadm/config_checks_enabled true' to enable -Enabled state (config_checks_enabled true) -:: +Enabled state (config_checks_enabled true): + +.. code-block:: bash CEPHADM 8/8 checks enabled and executed (0 bypassed, 0 disabled). No issues detected -The configuration checks themselves are managed through several cephadm sub-commands. +Managing Configuration Checks (subcommands) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To determine whether the configuration checks are enabled, you can use the following command -:: +The configuration checks themselves are managed through several cephadm subcommands. + +To determine whether the configuration checks are enabled, run the following command: + +.. prompt:: bash # ceph cephadm config-check status -This command will return the status of the configuration checker as either "Enabled" or "Disabled". +This command returns the status of the configuration checker as either "Enabled" or "Disabled". + +To list all the configuration checks and their current states, run the following command: -Listing all the configuration checks and their current state -:: +.. code-block:: console - ceph cephadm config-check ls + # ceph cephadm config-check ls - e.g. NAME HEALTHCHECK STATUS DESCRIPTION kernel_security CEPHADM_CHECK_KERNEL_LSM enabled checks SELINUX/Apparmor profiles are consistent across cluster hosts os_subscription CEPHADM_CHECK_SUBSCRIPTION enabled checks subscription states are consistent for all cluster hosts @@ -245,128 +316,191 @@ ceph_release CEPHADM_CHECK_CEPH_RELEASE enabled check for Ceph version consistency - ceph daemons should be on the same release (unless upgrade is active) kernel_version CEPHADM_CHECK_KERNEL_VERSION enabled checks that the MAJ.MIN of the kernel on Ceph hosts is consistent -The name of each configuration check, can then be used to enable or disable a specific check. -:: +The name of each configuration check can be used to enable or disable a specific check by running a command of the following form: +: + +.. prompt:: bash # ceph cephadm config-check disable - eg. +For example: + +.. prompt:: bash # + ceph cephadm config-check disable kernel_security CEPHADM_CHECK_KERNEL_LSM -^^^^^^^^^^^^^^^^^^^^^^^^ -Each host within the cluster is expected to operate within the same Linux Security Module (LSM) state. For example, -if the majority of the hosts are running with SELINUX in enforcing mode, any host not running in this mode -would be flagged as an anomaly and a healtcheck (WARNING) state raised. +~~~~~~~~~~~~~~~~~~~~~~~~ +Each host within the cluster is expected to operate within the same Linux +Security Module (LSM) state. For example, if the majority of the hosts are +running with SELINUX in enforcing mode, any host not running in this mode is +flagged as an anomaly and a healtcheck (WARNING) state raised. CEPHADM_CHECK_SUBSCRIPTION -^^^^^^^^^^^^^^^^^^^^^^^^^^ -This check relates to the status of vendor subscription. This check is only performed for hosts using RHEL, but helps -to confirm that all your hosts are covered by an active subscription so patches and updates -are available. +~~~~~~~~~~~~~~~~~~~~~~~~~~ +This check relates to the status of vendor subscription. This check is +performed only for hosts using RHEL, but helps to confirm that all hosts are +covered by an active subscription, which ensures that patches and updates are +available. CEPHADM_CHECK_PUBLIC_MEMBERSHIP -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -All members of the cluster should have NICs configured on at least one of the public network subnets. Hosts -that are not on the public network will rely on routing which may affect performance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +All members of the cluster should have NICs configured on at least one of the +public network subnets. Hosts that are not on the public network will rely on +routing, which may affect performance. CEPHADM_CHECK_MTU -^^^^^^^^^^^^^^^^^ -The MTU of the NICs on OSDs can be a key factor in consistent performance. This check examines hosts -that are running OSD services to ensure that the MTU is configured consistently within the cluster. This is -determined by establishing the MTU setting that the majority of hosts are using, with any anomalies being -resulting in a Ceph healthcheck. +~~~~~~~~~~~~~~~~~ +The MTU of the NICs on OSDs can be a key factor in consistent performance. This +check examines hosts that are running OSD services to ensure that the MTU is +configured consistently within the cluster. This is determined by establishing +the MTU setting that the majority of hosts is using. Any anomalies result in a +Ceph health check. CEPHADM_CHECK_LINKSPEED -^^^^^^^^^^^^^^^^^^^^^^^ -Similar to the MTU check, linkspeed consistency is also a factor in consistent cluster performance. -This check determines the linkspeed shared by the majority of "OSD hosts", resulting in a healthcheck for -any hosts that are set at a lower linkspeed rate. +~~~~~~~~~~~~~~~~~~~~~~~ +This check is similar to the MTU check. Linkspeed consistency is a factor in +consistent cluster performance, just as the MTU of the NICs on the OSDs is. +This check determines the linkspeed shared by the majority of OSD hosts, and a +health check is run for any hosts that are set at a lower linkspeed rate. CEPHADM_CHECK_NETWORK_MISSING -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The public_network and cluster_network settings support subnet definitions for IPv4 and IPv6. If these -settings are not found on any host in the cluster a healthcheck is raised. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The `public_network` and `cluster_network` settings support subnet definitions +for IPv4 and IPv6. If these settings are not found on any host in the cluster, +a health check is raised. CEPHADM_CHECK_CEPH_RELEASE -^^^^^^^^^^^^^^^^^^^^^^^^^^ -Under normal operations, the ceph cluster should be running daemons under the same ceph release (i.e. all -pacific). This check looks at the active release for each daemon, and reports any anomalies as a -healthcheck. *This check is bypassed if an upgrade process is active within the cluster.* +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Under normal operations, the Ceph cluster runs daemons under the same ceph +release (that is, the Ceph cluster runs all daemons under (for example) +Octopus). This check determines the active release for each daemon, and +reports any anomalies as a healthcheck. *This check is bypassed if an upgrade +process is active within the cluster.* CEPHADM_CHECK_KERNEL_VERSION -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The OS kernel version (maj.min) is checked for consistency across the hosts. Once again, the -majority of the hosts is used as the basis of identifying anomalies. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The OS kernel version (maj.min) is checked for consistency across the hosts. +The kernel version of the majority of the hosts is used as the basis for +identifying anomalies. + +.. _client_keyrings_and_configs: Client keyrings and configs =========================== -Cephadm can distribute copies of the ``ceph.conf`` and client keyring -files to hosts. For example, it is usually a good idea to store a -copy of the config and ``client.admin`` keyring on any hosts that will -be used to administer the cluster via the CLI. By default, cephadm will do -this for any nodes with the ``_admin`` label (which normally includes the bootstrap -host). +Cephadm can distribute copies of the ``ceph.conf`` file and client keyring +files to hosts. It is usually a good idea to store a copy of the config and +``client.admin`` keyring on any host used to administer the cluster via the +CLI. By default, cephadm does this for any nodes that have the ``_admin`` +label (which normally includes the bootstrap host). When a client keyring is placed under management, cephadm will: - - build a list of target hosts based on the specified placement spec (see :ref:`orchestrator-cli-placement-spec`) + - build a list of target hosts based on the specified placement spec (see + :ref:`orchestrator-cli-placement-spec`) - store a copy of the ``/etc/ceph/ceph.conf`` file on the specified host(s) - store a copy of the keyring file on the specified host(s) - update the ``ceph.conf`` file as needed (e.g., due to a change in the cluster monitors) - - update the keyring file if the entity's key is changed (e.g., via ``ceph auth ...`` commands) - - ensure the keyring file has the specified ownership and mode + - update the keyring file if the entity's key is changed (e.g., via ``ceph + auth ...`` commands) + - ensure that the keyring file has the specified ownership and specified mode - remove the keyring file when client keyring management is disabled - - remove the keyring file from old hosts if the keyring placement spec is updated (as needed) + - remove the keyring file from old hosts if the keyring placement spec is + updated (as needed) -To view which client keyrings are currently under management:: +Listing Client Keyrings +----------------------- + +To see the list of client keyrings are currently under management, run the following command: + +.. prompt:: bash # ceph orch client-keyring ls -To place a keyring under management:: +Putting a Keyring Under Management +---------------------------------- + +To put a keyring under management, run a command of the following form: + +.. prompt:: bash # ceph orch client-keyring set [--mode=] [--owner=.] [--path=] -- By default, the *path* will be ``/etc/ceph/client.{entity}.keyring``, which is where - Ceph looks by default. Be careful specifying alternate locations as existing files - may be overwritten. +- By default, the *path* is ``/etc/ceph/client.{entity}.keyring``, which is + where Ceph looks by default. Be careful when specifying alternate locations, + as existing files may be overwritten. - A placement of ``*`` (all hosts) is common. - The mode defaults to ``0600`` and ownership to ``0:0`` (user root, group root). -For example, to create and deploy a ``client.rbd`` key to hosts with the ``rbd-client`` label and group readable by uid/gid 107 (qemu),:: +For example, to create a ``client.rbd`` key and deploy it to hosts with the +``rbd-client`` label and make it group readable by uid/gid 107 (qemu), run the +following commands: + +.. prompt:: bash # ceph auth get-or-create-key client.rbd mon 'profile rbd' mgr 'profile rbd' osd 'profile rbd pool=my_rbd_pool' ceph orch client-keyring set client.rbd label:rbd-client --owner 107:107 --mode 640 -The resulting keyring file is:: +The resulting keyring file is: + +.. code-block:: console -rw-r-----. 1 qemu qemu 156 Apr 21 08:47 /etc/ceph/client.client.rbd.keyring -To disable management of a keyring file:: +Disabling Management of a Keyring File +-------------------------------------- + +To disable management of a keyring file, run a command of the following form: + +.. prompt:: bash # ceph orch client-keyring rm -Note that this will delete any keyring files for this entity that were previously written -to cluster nodes. +.. note:: + + This deletes any keyring files for this entity that were previously written + to cluster nodes. +.. _etc_ceph_conf_distribution: /etc/ceph/ceph.conf =================== -It may also be useful to distribute ``ceph.conf`` files to hosts without an associated -client keyring file. By default, cephadm only deploys a ``ceph.conf`` file to hosts where a client keyring -is also distributed (see above). To write config files to hosts without client keyrings:: +Distributing ceph.conf to hosts that have no keyrings +----------------------------------------------------- + +It might be useful to distribute ``ceph.conf`` files to hosts without an +associated client keyring file. By default, cephadm deploys only a +``ceph.conf`` file to hosts where a client keyring is also distributed (see +above). To write config files to hosts without client keyrings, run the +following command: + +.. prompt:: bash # ceph config set mgr mgr/cephadm/manage_etc_ceph_ceph_conf true -By default, the configs are written to all hosts (i.e., those listed -by ``ceph orch host ls``). To specify which hosts get a ``ceph.conf``:: +Using Placement Specs to specify which hosts get keyrings +--------------------------------------------------------- + +By default, the configs are written to all hosts (i.e., those listed by ``ceph +orch host ls``). To specify which hosts get a ``ceph.conf``, run a command of +the following form: + +.. prompt:: bash # + + ceph config set mgr mgr/cephadm/manage_etc_ceph_ceph_conf_hosts + +For example, to distribute configs to hosts with the ``bare_config`` label, run +the following command: + +Distributing ceph.conf to hosts tagged with bare_config +------------------------------------------------------- - ceph config set mgr mgr/cephadm/manage_etc_ceph_ceph_conf_hosts +For example, to distribute configs to hosts with the ``bare_config`` label, run the following command: -For example, to distribute configs to hosts with the ``bare_config`` label,:: +.. prompt:: bash # - ceph config set mgr mgr/cephadm/manage_etc_ceph_ceph_conf_hosts label:bare_config + ceph config set mgr mgr/cephadm/manage_etc_ceph_ceph_conf_hosts label:bare_config (See :ref:`orchestrator-cli-placement-spec` for more information about placement specs.) diff -Nru ceph-16.2.5/doc/cephadm/osd.rst ceph-16.2.6/doc/cephadm/osd.rst --- ceph-16.2.5/doc/cephadm/osd.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/osd.rst 2021-09-16 14:27:19.000000000 +0000 @@ -7,7 +7,7 @@ List Devices ============ -``ceph-volume`` scans each cluster in the host from time to time in order +``ceph-volume`` scans each host in the cluster from time to time in order to determine which devices are present and whether they are eligible to be used as OSDs. @@ -211,6 +211,7 @@ * For cephadm, see also :ref:`cephadm-spec-unmanaged`. +.. _cephadm-osd-removal: Remove an OSD ============= @@ -347,7 +348,7 @@ .. prompt:: bash # - orch device zap + ceph orch device zap Example command: diff -Nru ceph-16.2.5/doc/cephadm/rgw.rst ceph-16.2.6/doc/cephadm/rgw.rst --- ceph-16.2.5/doc/cephadm/rgw.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/rgw.rst 2021-09-16 14:27:19.000000000 +0000 @@ -82,6 +82,41 @@ See :ref:`orchestrator-cli-placement-spec` for details of the placement specification. See :ref:`multisite` for more information of setting up multisite RGW. +Setting up HTTPS +---------------- + +In order to enable HTTPS for RGW services, apply a spec file following this scheme: + +.. code-block:: yaml + + service_type: rgw + service_id: myrgw + spec: + rgw_frontend_ssl_certificate: | + -----BEGIN PRIVATE KEY----- + V2VyIGRhcyBsaWVzdCBpc3QgZG9vZi4gTG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFt + ZXQsIGNvbnNldGV0dXIgc2FkaXBzY2luZyBlbGl0ciwgc2VkIGRpYW0gbm9udW15 + IGVpcm1vZCB0ZW1wb3IgaW52aWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu + YSBhbGlxdXlhbSBlcmF0LCBzZWQgZGlhbSB2b2x1cHR1YS4gQXQgdmVybyBlb3Mg + ZXQgYWNjdXNhbSBldCBqdXN0byBkdW8= + -----END PRIVATE KEY----- + -----BEGIN CERTIFICATE----- + V2VyIGRhcyBsaWVzdCBpc3QgZG9vZi4gTG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFt + ZXQsIGNvbnNldGV0dXIgc2FkaXBzY2luZyBlbGl0ciwgc2VkIGRpYW0gbm9udW15 + IGVpcm1vZCB0ZW1wb3IgaW52aWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu + YSBhbGlxdXlhbSBlcmF0LCBzZWQgZGlhbSB2b2x1cHR1YS4gQXQgdmVybyBlb3Mg + ZXQgYWNjdXNhbSBldCBqdXN0byBkdW8= + -----END CERTIFICATE----- + ssl: true + +Then apply this yaml document: + +.. prompt:: bash # + + ceph orch apply -i myrgw.yaml + +Note the value of ``rgw_frontend_ssl_certificate`` is a literal string as +indicated by a ``|`` character preserving newline characters. .. _orchestrator-haproxy-service-spec: diff -Nru ceph-16.2.5/doc/cephadm/service-management.rst ceph-16.2.6/doc/cephadm/service-management.rst --- ceph-16.2.5/doc/cephadm/service-management.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/service-management.rst 2021-09-16 14:27:19.000000000 +0000 @@ -158,6 +158,54 @@ cephadm will not deploy daemons on hosts with the ``_no_schedule`` label; see :ref:`cephadm-special-host-labels`. + .. note:: + The **apply** command can be confusing. For this reason, we recommend using + YAML specifications. + + Each ``ceph orch apply `` command supersedes the one before it. + If you do not use the proper syntax, you will clobber your work + as you go. + + For example: + + .. prompt:: bash # + + ceph orch apply mon host1 + ceph orch apply mon host2 + ceph orch apply mon host3 + + This results in only one host having a monitor applied to it: host 3. + + (The first command creates a monitor on host1. Then the second command + clobbers the monitor on host1 and creates a monitor on host2. Then the + third command clobbers the monitor on host2 and creates a monitor on + host3. In this scenario, at this point, there is a monitor ONLY on + host3.) + + To make certain that a monitor is applied to each of these three hosts, + run a command like this: + + .. prompt:: bash # + + ceph orch apply mon "host1,host2,host3" + + There is another way to apply monitors to multiple hosts: a ``yaml`` file + can be used. Instead of using the "ceph orch apply mon" commands, run a + command of this form: + + .. prompt:: bash # + + ceph orch apply -i file.yaml + + Here is a sample **file.yaml** file:: + + service_type: mon + placement: + hosts: + - host1 + - host2 + - host3 + Explicit placements ------------------- @@ -192,7 +240,39 @@ Placement by labels ------------------- -Daemons can be explicitly placed on hosts that match a specific label: +Daemon placement can be limited to hosts that match a specific label. To set +a label ``mylabel`` to the appropriate hosts, run this command: + + .. prompt:: bash # + + ceph orch host label add ** mylabel + + To view the current hosts and labels, run this command: + + .. prompt:: bash # + + ceph orch host ls + + For example: + + .. prompt:: bash # + + ceph orch host label add host1 mylabel + ceph orch host label add host2 mylabel + ceph orch host label add host3 mylabel + ceph orch host ls + + .. code-block:: bash + + HOST ADDR LABELS STATUS + host1 mylabel + host2 mylabel + host3 mylabel + host4 + host5 + +Now, Tell cephadm to deploy daemons based on the label by running +this command: .. prompt:: bash # @@ -240,8 +320,8 @@ host_pattern: "*" -Setting a limit ---------------- +Changing the number of monitors +------------------------------- By specifying ``count``, only the number of daemons specified will be created: @@ -402,7 +482,17 @@ Deploying a daemon on a host manually ------------------------------------- -To manually deploy a daemon on a host, run a command of the following form: +.. note:: + + This workflow has a very limited use case and should only be used + in rare circumstances. + +To manually deploy a daemon on a host, follow these steps: + +Modify the service spec for a service by getting the +existing spec, adding ``unmanaged: true``, and applying the modified spec. + +Then manually deploy the daemon using the following: .. prompt:: bash # @@ -414,6 +504,13 @@ ceph orch daemon add mgr --placement=my_host +.. note:: + + Removing ``unmanaged: true`` from the service spec will + enable the reconciliation loop for this service and will + potentially lead to the removal of the daemon, depending + on the placement spec. + Removing a daemon from a host manually -------------------------------------- diff -Nru ceph-16.2.5/doc/cephadm/troubleshooting.rst ceph-16.2.6/doc/cephadm/troubleshooting.rst --- ceph-16.2.5/doc/cephadm/troubleshooting.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/troubleshooting.rst 2021-09-16 14:27:19.000000000 +0000 @@ -1,46 +1,70 @@ Troubleshooting =============== -Sometimes there is a need to investigate why a cephadm command failed or why -a specific service no longer runs properly. +You might need to investigate why a cephadm command failed +or why a certain service no longer runs properly. -As cephadm deploys daemons as containers, troubleshooting daemons is slightly -different. Here are a few tools and commands to help investigating issues. +Cephadm deploys daemons as containers. This means that +troubleshooting those containerized daemons might work +differently than you expect (and that is certainly true if +you expect this troubleshooting to work the way that +troubleshooting does when the daemons involved aren't +containerized). + +Here are some tools and commands to help you troubleshoot +your Ceph environment. .. _cephadm-pause: Pausing or disabling cephadm ---------------------------- -If something goes wrong and cephadm is doing behaving in a way you do -not like, you can pause most background activity with:: +If something goes wrong and cephadm is behaving badly, you can +pause most of the Ceph cluster's background activity by running +the following command: + +.. prompt:: bash # ceph orch pause -This will stop any changes, but cephadm will still periodically check hosts to -refresh its inventory of daemons and devices. You can disable cephadm -completely with:: +This stops all changes in the Ceph cluster, but cephadm will +still periodically check hosts to refresh its inventory of +daemons and devices. You can disable cephadm completely by +running the following commands: + +.. prompt:: bash # ceph orch set backend '' ceph mgr module disable cephadm -This will disable all of the ``ceph orch ...`` CLI commands but the previously -deployed daemon containers will still continue to exist and start as they -did before. +These commands disable all of the ``ceph orch ...`` CLI commands. +All previously deployed daemon containers continue to exist and +will start as they did before you ran these commands. -Please refer to :ref:`cephadm-spec-unmanaged` for disabling individual -services. +See :ref:`cephadm-spec-unmanaged` for information on disabling +individual services. Per-service and per-daemon events --------------------------------- -In order to aid debugging failed daemon deployments, cephadm stores -events per service and per daemon. They often contain relevant information:: +In order to help with the process of debugging failed daemon +deployments, cephadm stores events per service and per daemon. +These events often contain information relevant to +troubleshooting +your Ceph cluster. + +Listing service events +~~~~~~~~~~~~~~~~~~~~~~ + +To see the events associated with a certain service, run a +command of the and following form: + +.. prompt:: bash # ceph orch ls --service_name= --format yaml -for example: +This will return something in the following form: .. code-block:: yaml @@ -58,10 +82,18 @@ - '2021-02-01T12:09:25.264584 service:alertmanager [ERROR] "Failed to apply: Cannot place on unknown_host: Unknown hosts"' -Or per daemon:: +Listing daemon events +~~~~~~~~~~~~~~~~~~~~~ + +To see the events associated with a certain daemon, run a +command of the and following form: + +.. prompt:: bash # ceph orch ps --service-name --daemon-id --format yaml +This will return something in the following form: + .. code-block:: yaml daemon_type: mds @@ -77,16 +109,11 @@ Checking cephadm logs --------------------- -You can monitor the cephadm log in real time with:: - - ceph -W cephadm +To learn how to monitor the cephadm logs as they are generated, read :ref:`watching_cephadm_logs`. -You can see the last few messages with:: - - ceph log last cephadm - -If you have enabled logging to files, you can see a cephadm log file called -``ceph.cephadm.log`` on monitor hosts (see :ref:`cephadm-logs`). +If your Ceph cluster has been configured to log events to files, there will exist a +cephadm log file called ``ceph.cephadm.log`` on all monitor hosts (see +:ref:`cephadm-logs` for a more complete explanation of this). Gathering log files ------------------- @@ -190,7 +217,8 @@ [root@mon1 ~]# ssh -F config -i ~/cephadm_private_key root@mon1 Verifying that the Public Key is Listed in the authorized_keys file -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + To verify that the public key is in the authorized_keys file, run the following commands:: [root@mon1 ~]# cephadm shell -- ceph cephadm get-pub-key > ~/ceph.pub diff -Nru ceph-16.2.5/doc/cephadm/upgrade.rst ceph-16.2.6/doc/cephadm/upgrade.rst --- ceph-16.2.5/doc/cephadm/upgrade.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephadm/upgrade.rst 2021-09-16 14:27:19.000000000 +0000 @@ -12,26 +12,32 @@ * Each daemon is restarted only after Ceph indicates that the cluster will remain available. -Keep in mind that the Ceph cluster health status is likely to switch to -``HEALTH_WARNING`` during the upgrade. +.. note:: + + The Ceph cluster health status is likely to switch to + ``HEALTH_WARNING`` during the upgrade. + +.. note:: + + In case a host of the cluster is offline, the upgrade is paused. Starting the upgrade ==================== -Before you begin using cephadm to upgrade Ceph, verify that all hosts are currently online and that your cluster is healthy: +Before you use cephadm to upgrade Ceph, verify that all hosts are currently online and that your cluster is healthy by running the following command: .. prompt:: bash # ceph -s -To upgrade (or downgrade) to a specific release: +To upgrade (or downgrade) to a specific release, run the following command: .. prompt:: bash # ceph orch upgrade start --ceph-version -For example, to upgrade to v15.2.1: +For example, to upgrade to v15.2.1, run the following command: .. prompt:: bash # @@ -76,11 +82,11 @@ Canceling an upgrade ==================== -You can stop the upgrade process at any time with: +You can stop the upgrade process at any time by running the following command: .. prompt:: bash # - # ceph orch upgrade stop + ceph orch upgrade stop Potential problems @@ -91,22 +97,27 @@ UPGRADE_NO_STANDBY_MGR ---------------------- -This alert means that Ceph requires an active and standby manager daemon in -order to proceed, but there is currently no standby. +This alert (``UPGRADE_NO_STANDBY_MGR``) means that Ceph does not detect an +active standby manager daemon. In order to proceed with the upgrade, Ceph +requires an active standby manager daemon (which you can think of in this +context as "a second manager"). -You can ensure that Cephadm is configured to run 2 (or more) managers by running the following command: +You can ensure that Cephadm is configured to run 2 (or more) managers by +running the following command: .. prompt:: bash # ceph orch apply mgr 2 # or more -You can check the status of existing mgr daemons by running the following command: +You can check the status of existing mgr daemons by running the following +command: .. prompt:: bash # ceph orch ps --daemon-type mgr -If an existing mgr daemon has stopped, you can try to restart it by running the following command: +If an existing mgr daemon has stopped, you can try to restart it by running the +following command: .. prompt:: bash # @@ -115,12 +126,13 @@ UPGRADE_FAILED_PULL ------------------- -This alert means that Ceph was unable to pull the container image for the -target version. This can happen if you specify a version or container image -that does not exist (e.g. "1.2.3"), or if the container registry can not -be reached by one or more hosts in the cluster. +This alert (``UPGRADE_FAILED_PULL``) means that Ceph was unable to pull the +container image for the target version. This can happen if you specify a +version or container image that does not exist (e.g. "1.2.3"), or if the +container registry can not be reached by one or more hosts in the cluster. -To cancel the existing upgrade and to specify a different target version, run the following commands: +To cancel the existing upgrade and to specify a different target version, run +the following commands: .. prompt:: bash # diff -Nru ceph-16.2.5/doc/cephfs/administration.rst ceph-16.2.6/doc/cephfs/administration.rst --- ceph-16.2.5/doc/cephfs/administration.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephfs/administration.rst 2021-09-16 14:27:19.000000000 +0000 @@ -351,24 +351,6 @@ :: - mds compat rm_compat - -Removes an compatibility feature flag. - -:: - - mds compat rm_incompat - -Removes an incompatibility feature flag. - -:: - - mds compat show - -Show MDS compatibility flags. - -:: - mds rmfailed This removes a rank from the failed set. @@ -379,3 +361,14 @@ This command resets the file system state to defaults, except for the name and pools. Non-zero ranks are saved in the stopped set. + + +:: + + fs new --fscid --force + +This command creates a file system with a specific **fscid** (file system cluster ID). +You may want to do this when an application expects the file system's ID to be +stable after it has been recovered, e.g., after monitor databases are lost and +rebuilt. Consequently, file system IDs don't always keep increasing with newer +file systems. diff -Nru ceph-16.2.5/doc/cephfs/fs-nfs-exports.rst ceph-16.2.6/doc/cephfs/fs-nfs-exports.rst --- ceph-16.2.5/doc/cephfs/fs-nfs-exports.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephfs/fs-nfs-exports.rst 2021-09-16 14:27:19.000000000 +0000 @@ -15,6 +15,53 @@ .. note:: From Pacific, the nfs mgr module must be enabled prior to use. +Ganesha Configuration Hierarchy +=============================== + +Cephadm and rook starts nfs-ganesha daemon with `bootstrap configuration` +containing minimal ganesha configuration, creates empty rados `common config` +object in `nfs-ganesha` pool and watches this config object. The `mgr/nfs` +module adds rados export object urls to the common config object. If cluster +config is set, it creates `user config` object containing custom ganesha +configuration and adds it url to common config object. + +.. ditaa:: + + + rados://$pool/$namespace/export-$i rados://$pool/$namespace/userconf-nfs.$cluster_id + (export config) (user config) + + +----------+ +----------+ +----------+ +---------------------------+ + | | | | | | | | + | export-1 | | export-2 | | export-3 | | userconf-nfs.$cluster_id | + | | | | | | | | + +----+-----+ +----+-----+ +-----+----+ +-------------+-------------+ + ^ ^ ^ ^ + | | | | + +--------------------------------+-------------------------+ + %url | + | + +--------+--------+ + | | rados://$pool/$namespace/conf-nfs.$svc + | conf+nfs.$svc | (common config) + | | + +--------+--------+ + ^ + | + watch_url | + +----------------------------------------------+ + | | | + | | | RADOS + +----------------------------------------------------------------------------------+ + | | | CONTAINER + watch_url | watch_url | watch_url | + | | | + +--------+-------+ +--------+-------+ +-------+--------+ + | | | | | | /etc/ganesha/ganesha.conf + | nfs.$svc.a | | nfs.$svc.b | | nfs.$svc.c | (bootstrap config) + | | | | | | + +----------------+ +----------------+ +----------------+ + Create NFS Ganesha Cluster ========================== diff -Nru ceph-16.2.5/doc/cephfs/upgrading.rst ceph-16.2.6/doc/cephfs/upgrading.rst --- ceph-16.2.5/doc/cephfs/upgrading.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/cephfs/upgrading.rst 2021-09-16 14:27:19.000000000 +0000 @@ -6,13 +6,11 @@ assertions or other faults due to incompatible messages or other functional differences. For this reason, it's necessary during any cluster upgrade to reduce the number of active MDS for a file system to one first so that two -active MDS do not communicate with different versions. Further, it's also -necessary to take standbys offline as any new CompatSet flags will propagate -via the MDSMap to all MDS and cause older MDS to suicide. +active MDS do not communicate with different versions. The proper sequence for upgrading the MDS cluster is: -1. Disable and stop standby-replay daemons. +1. For each file system, disable and stop standby-replay daemons. :: @@ -27,7 +25,7 @@ ceph mds fail mds. -2. Reduce the number of ranks to 1: +2. For each file system, reduce the number of ranks to 1: :: @@ -39,43 +37,20 @@ ceph status # wait for MDS to finish stopping -4. Take all standbys offline, e.g. using systemctl: - -:: - - systemctl stop ceph-mds.target - -5. Confirm only one MDS is online and is rank 0 for your FS: - -:: - - ceph status - -6. Upgrade the single active MDS, e.g. using systemctl: - -:: - - # use package manager to update cluster - systemctl restart ceph-mds.target - -7. Upgrade/start the standby daemons. +4. For each MDS, upgrade packages and restart. Note: to reduce failovers, it is + recommended -- but not strictly necessary -- to first upgrade standby daemons. :: # use package manager to update cluster systemctl restart ceph-mds.target -8. Restore the previous max_mds for your cluster: +5. For each file system, restore the previous max_mds and allow_standby_replay settings for your cluster: :: ceph fs set max_mds - -9. Restore setting for ``allow_standby_replay`` (if applicable): - -:: - - ceph fs set allow_standby_replay true + ceph fs set allow_standby_replay Upgrading pre-Firefly file systems past Jewel diff -Nru ceph-16.2.5/doc/ceph-volume/index.rst ceph-16.2.6/doc/ceph-volume/index.rst --- ceph-16.2.5/doc/ceph-volume/index.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/ceph-volume/index.rst 2021-09-16 14:27:19.000000000 +0000 @@ -76,6 +76,9 @@ lvm/systemd lvm/list lvm/zap + lvm/migrate + lvm/newdb + lvm/newwal simple/index simple/activate simple/scan diff -Nru ceph-16.2.5/doc/ceph-volume/lvm/index.rst ceph-16.2.6/doc/ceph-volume/lvm/index.rst --- ceph-16.2.5/doc/ceph-volume/lvm/index.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/ceph-volume/lvm/index.rst 2021-09-16 14:27:19.000000000 +0000 @@ -15,6 +15,12 @@ * :ref:`ceph-volume-lvm-list` +* :ref:`ceph-volume-lvm-migrate` + +* :ref:`ceph-volume-lvm-newdb` + +* :ref:`ceph-volume-lvm-newwal` + .. not yet implemented .. * :ref:`ceph-volume-lvm-scan` diff -Nru ceph-16.2.5/doc/ceph-volume/lvm/migrate.rst ceph-16.2.6/doc/ceph-volume/lvm/migrate.rst --- ceph-16.2.5/doc/ceph-volume/lvm/migrate.rst 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/doc/ceph-volume/lvm/migrate.rst 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,47 @@ +.. _ceph-volume-lvm-migrate: + +``migrate`` +=========== + +Moves BlueFS data from source volume(s) to the target one, source volumes +(except the main, i.e. data or block one) are removed on success. + +LVM volumes are permitted for Target only, both already attached or new one. + +In the latter case it is attached to the OSD replacing one of the source +devices. + +Following replacement rules apply (in the order of precedence, stop +on the first match): + + - if source list has DB volume - target device replaces it. + - if source list has WAL volume - target device replaces it. + - if source list has slow volume only - operation is not permitted, + requires explicit allocation via new-db/new-wal command. + +Moves BlueFS data from main device to LV already attached as DB:: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data --target vgname/db + +Moves BlueFS data from shared main device to LV which will be attached as a +new DB:: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data --target vgname/new_db + +Moves BlueFS data from DB device to new LV, DB is replaced:: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from db --target vgname/new_db + +Moves BlueFS data from main and DB devices to new LV, DB is replaced:: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data db --target vgname/new_db + +Moves BlueFS data from main, DB and WAL devices to new LV, WAL is removed and +DB is replaced:: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data db wal --target vgname/new_db + +Moves BlueFS data from main, DB and WAL devices to main device, WAL and DB are +removed:: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from db wal --target vgname/data diff -Nru ceph-16.2.5/doc/ceph-volume/lvm/newdb.rst ceph-16.2.6/doc/ceph-volume/lvm/newdb.rst --- ceph-16.2.5/doc/ceph-volume/lvm/newdb.rst 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/doc/ceph-volume/lvm/newdb.rst 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,11 @@ +.. _ceph-volume-lvm-newdb: + +``new-db`` +=========== + +Attaches the given logical volume to OSD as a DB. +Logical volume name format is vg/lv. Fails if OSD has already got attached DB. + +Attach vgname/lvname as a DB volume to OSD 1:: + + ceph-volume lvm new-db --osd-id 1 --osd-fsid 55BD4219-16A7-4037-BC20-0F158EFCC83D --target vgname/new_db diff -Nru ceph-16.2.5/doc/ceph-volume/lvm/newwal.rst ceph-16.2.6/doc/ceph-volume/lvm/newwal.rst --- ceph-16.2.5/doc/ceph-volume/lvm/newwal.rst 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/doc/ceph-volume/lvm/newwal.rst 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,11 @@ +.. _ceph-volume-lvm-newwal: + +``new-wal`` +=========== + +Attaches the given logical volume to the given OSD as a WAL volume. +Logical volume format is vg/lv. Fails if OSD has already got attached DB. + +Attach vgname/lvname as a WAL volume to OSD 1:: + + ceph-volume lvm new-wal --osd-id 1 --osd-fsid 55BD4219-16A7-4037-BC20-0F158EFCC83D --target vgname/new_wal diff -Nru ceph-16.2.5/doc/dev/cephadm/developing-cephadm.rst ceph-16.2.6/doc/dev/cephadm/developing-cephadm.rst --- ceph-16.2.5/doc/dev/cephadm/developing-cephadm.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/dev/cephadm/developing-cephadm.rst 2021-09-16 14:27:19.000000000 +0000 @@ -124,6 +124,20 @@ As a guideline, cephadm should do at most ``O(1)`` network calls in CLI handlers. Everything else should be done asynchronously in other threads, like ``serve()``. +Note regarding different variables used in the code +=================================================== + +* a ``service_type`` is something like mon, mgr, alertmanager etc defined + in ``ServiceSpec`` +* a ``service_id`` is the name of the service. Some services don't have + names. +* a ``service_name`` is ``.`` +* a ``daemon_type`` is the same as the service_type, except for ingress, + which has the haproxy and keepalived daemon types. +* a ``daemon_id`` is typically ``..``. + (Not the case for e.g. OSDs. OSDs are always called OSD.N) +* a ``daemon_name`` is ``.`` + Kcli: a virtualization management tool to make easy orchestrators development ============================================================================= `Kcli `_ is meant to interact with existing diff -Nru ceph-16.2.5/doc/dev/developer_guide/dash-devel.rst ceph-16.2.6/doc/dev/developer_guide/dash-devel.rst --- ceph-16.2.5/doc/dev/developer_guide/dash-devel.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/dev/developer_guide/dash-devel.rst 2021-09-16 14:27:19.000000000 +0000 @@ -430,7 +430,14 @@ Orchestrator backend behave correctly. Prerequisites: you need to install `KCLI -`_ in your local machine. +`_ and Node.js in your local machine. + +Configure KCLI plan requirements:: + + $ sudo chown -R $(id -un) /var/lib/libvirt/images + $ mkdir -p /var/lib/libvirt/images/ceph-dashboard dashboard + $ kcli create pool -p /var/lib/libvirt/images/ceph-dashboard dashboard + $ kcli create network -c 192.168.100.0/24 dashboard Note: This script is aimed to be run as jenkins job so the cleanup is triggered only in a jenkins @@ -439,9 +446,26 @@ Start E2E tests by running:: $ cd - $ sudo chown -R $(id -un) src/pybind/mgr/dashboard/frontend/dist src/pybind/mgr/dashboard/frontend/node_modules + $ sudo chown -R $(id -un) src/pybind/mgr/dashboard/frontend/{dist,node_modules,src/environments} $ ./src/pybind/mgr/dashboard/ci/cephadm/run-cephadm-e2e-tests.sh - $ kcli delete plan -y ceph # After tests finish. + +You can also start a cluster in development mode (so the frontend build starts in watch mode and you +only have to reload the page for the changes to be reflected) by running:: + + $ ./src/pybind/mgr/dashboard/ci/cephadm/start-cluster.sh --dev-mode + +Note: + Add ``--expanded`` if you need a cluster ready to deploy services (one with enough monitor + daemons spread across different hosts and enough OSDs). + +Test your changes by running: + + $ ./src/pybind/mgr/dashboard/ci/cephadm/run-cephadm-e2e-tests.sh + +Shutdown the cluster by running: + + $ kcli delete plan -y ceph + $ # In development mode, also kill the npm build watch process (e.g., pkill -f "ng build") Other running options ..................... @@ -1652,6 +1676,58 @@ loading the ``Ping`` controller. We can also disable authentication of a controller at this stage, as depicted in the example. +How to update or create new dashboards in grafana? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We are using ``jsonnet`` and ``grafonnet-lib`` to write code for the grafana dashboards. +All the dashboards are written inside ``grafana_dashboards.jsonnet`` file in the +monitoring/grafana/dashboards/jsonnet directory. + +We generate the dashboard json files directly from this jsonnet file by running this +command in the grafana/dashboards directory: +``jsonnet -m . jsonnet/grafana_dashboards.jsonnet``. +(For the above command to succeed we need ``jsonnet`` package installed and ``grafonnet-lib`` +directory cloned in our machine. Please refer - +``https://grafana.github.io/grafonnet-lib/getting-started/`` in case you have some trouble.) + +To update an existing grafana dashboard or to create a new one, we need to update +the ``grafana_dashboards.jsonnet`` file and generate the new/updated json files using the +above mentioned command. For people who are not familiar with grafonnet or jsonnet implementation +can follow this doc - ``https://grafana.github.io/grafonnet-lib/``. + +Example grafana dashboard in jsonnet format: + +To specify the grafana dashboard properties such as title, uid etc we can create a local function - + +:: + + local dashboardSchema(title, uid, time_from, refresh, schemaVersion, tags,timezone, timepicker) + +To add a graph panel we can spcify the graph schema in a local function such as - + +:: + + local graphPanelSchema(title, nullPointMode, stack, formatY1, formatY2, labelY1, labelY2, min, fill, datasource) + +and then use these functions inside the dashboard definition like - + +:: + + { + radosgw-sync-overview.json: //json file name to be generated + + dashboardSchema( + 'RGW Sync Overview', 'rgw-sync-overview', 'now-1h', '15s', .., .., .. + ) + + .addPanels([ + graphPanelSchema( + 'Replication (throughput) from Source Zone', 'Bps', null, .., .., ..) + ]) + } + +The valid grafonnet-lib attributes can be found here - ``https://grafana.github.io/grafonnet-lib/api-docs/``. + How to listen for manager notifications in a controller? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff -Nru ceph-16.2.5/doc/_ext/ceph_commands.py ceph-16.2.6/doc/_ext/ceph_commands.py --- ceph-16.2.5/doc/_ext/ceph_commands.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/_ext/ceph_commands.py 2021-09-16 14:27:19.000000000 +0000 @@ -254,6 +254,7 @@ 'jsonpatch', 'rook.rook_client', 'rook.rook_client.ceph', + 'rook.rook_client._helper', 'cherrypy=3.2.3'] # make restful happy diff -Nru ceph-16.2.5/doc/install/containers.rst ceph-16.2.6/doc/install/containers.rst --- ceph-16.2.5/doc/install/containers.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/install/containers.rst 2021-09-16 14:27:19.000000000 +0000 @@ -19,11 +19,11 @@ Official Releases ----------------- -Ceph Container images are available from Docker Hub at:: +Ceph Container images are available from both Quay and Docker Hub:: + https://quay.io/repository/ceph/ceph https://hub.docker.com/r/ceph - ceph/ceph ^^^^^^^^^ @@ -42,6 +42,13 @@ | vRELNUM.Y.Z-YYYYMMDD | A specific build (e.g., *v14.2.4-20191203*) | +----------------------+--------------------------------------------------------------+ +Legacy container images +----------------------- + +Legacy container images are available from Docker Hub at:: + + https://hub.docker.com/r/ceph + ceph/daemon-base ^^^^^^^^^^^^^^^^ diff -Nru ceph-16.2.5/doc/man/8/cephadm.rst ceph-16.2.6/doc/man/8/cephadm.rst --- ceph-16.2.5/doc/man/8/cephadm.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/man/8/cephadm.rst 2021-09-16 14:27:19.000000000 +0000 @@ -53,6 +53,7 @@ | **cephadm** **bootstrap** [-h] [--config CONFIG] [--mon-id MON_ID] | [--mon-addrv MON_ADDRV] [--mon-ip MON_IP] | [--mgr-id MGR_ID] [--fsid FSID] +| [--log-to-file] [--single-host-defaults] | [--output-dir OUTPUT_DIR] | [--output-keyring OUTPUT_KEYRING] | [--output-config OUTPUT_CONFIG] @@ -126,13 +127,14 @@ .. option:: --docker use docker instead of podman (default: False) -.. option::data-dir DATA_DIR - base directory for daemon data (default:/var/lib/ceph) +.. option:: --data-dir DATA_DIR + + base directory for daemon data (default: /var/lib/ceph) .. option:: --log-dir LOG_DIR - base directory for daemon logs (default:.. option:: /var/log/ceph) + base directory for daemon logs (default: /var/log/ceph) .. option:: --logrotate-dir LOGROTATE_DIR @@ -208,6 +210,8 @@ * [--mon-ip MON_IP] mon IP * [--mgr-id MGR_ID] mgr id (default: randomly generated) * [--fsid FSID] cluster FSID +* [--log-to-file] configure cluster to log to traditional log files +* [--single-host-defaults] configure cluster to run on a single host * [--output-dir OUTPUT_DIR] directory to write config, keyring, and pub key files * [--output-keyring OUTPUT_KEYRING] location to write keyring file with new cluster admin and mon keys * [--output-config OUTPUT_CONFIG] location to write conf file to connect to new cluster diff -Nru ceph-16.2.5/doc/man/8/ceph-volume.rst ceph-16.2.6/doc/man/8/ceph-volume.rst --- ceph-16.2.5/doc/man/8/ceph-volume.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/man/8/ceph-volume.rst 2021-09-16 14:27:19.000000000 +0000 @@ -15,7 +15,7 @@ | **ceph-volume** **inventory** | **ceph-volume** **lvm** [ *trigger* | *create* | *activate* | *prepare* -| *zap* | *list* | *batch*] +| *zap* | *list* | *batch* | *new-wal* | *new-db* | *migrate* ] | **ceph-volume** **simple** [ *trigger* | *scan* | *activate* ] @@ -241,6 +241,96 @@ ``/path/to/sda1`` or ``/path/to/sda`` for regular devices. +new-wal +^^^^^^^ + +Attaches the given logical volume to OSD as a WAL. Logical volume +name format is vg/lv. Fails if OSD has already got attached WAL. + +Usage:: + + ceph-volume lvm new-wal --osd-id OSD_ID --osd-fsid OSD_FSID --target + +Optional arguments: + +.. option:: -h, --help + + show the help message and exit + +.. option:: --no-systemd + + Skip checking OSD systemd unit + +Required arguments: + +.. option:: --target + + logical volume name to attach as WAL + +new-db +^^^^^^ + +Attaches the given logical volume to OSD as a DB. Logical volume +name format is vg/lv. Fails if OSD has already got attached DB. + +Usage:: + + ceph-volume lvm new-db --osd-id OSD_ID --osd-fsid OSD_FSID --target + +Optional arguments: + +.. option:: -h, --help + + show the help message and exit + +.. option:: --no-systemd + + Skip checking OSD systemd unit + +Required arguments: + +.. option:: --target + + logical volume name to attach as DB + +migrate +^^^^^^^ + +Moves BlueFS data from source volume(s) to the target one, source volumes +(except the main, i.e. data or block one) are removed on success. LVM volumes +are permitted for Target only, both already attached or new one. In the latter +case it is attached to the OSD replacing one of the source devices. Following +replacement rules apply (in the order of precedence, stop on the first match): + + - if source list has DB volume - target device replaces it. + - if source list has WAL volume - target device replace it. + - if source list has slow volume only - operation is not permitted, + requires explicit allocation via new-db/new-wal command. + +Usage:: + + ceph-volume lvm migrate --osd-id OSD_ID --osd-fsid OSD_FSID --target --from {data|db|wal} [{data|db|wal} ...] + +Optional arguments: + +.. option:: -h, --help + + show the help message and exit + +.. option:: --no-systemd + + Skip checking OSD systemd unit + +Required arguments: + +.. option:: --from + + list of source device type names + +.. option:: --target + + logical volume to move data to + simple ------ diff -Nru ceph-16.2.5/doc/mgr/dashboard_plugins/motd.inc.rst ceph-16.2.6/doc/mgr/dashboard_plugins/motd.inc.rst --- ceph-16.2.5/doc/mgr/dashboard_plugins/motd.inc.rst 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/doc/mgr/dashboard_plugins/motd.inc.rst 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,30 @@ +.. _dashboard-motd: + +Message of the day (MOTD) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Displays a configured `message of the day` at the top of the Ceph Dashboard. + +The importance of a MOTD can be configured by its severity, which is +`info`, `warning` or `danger`. The MOTD can expire after a given time, +this means it will not be displayed in the UI anymore. Use the following +syntax to specify the expiration time: `Ns|m|h|d|w` for seconds, minutes, +hours, days and weeks. If the MOTD should expire after 2 hours, use `2h` +or `5w` for 5 weeks. Use `0` to configure a MOTD that does not expire. + +To configure a MOTD, run the following command:: + + $ ceph dashboard motd set + +To show the configured MOTD:: + + $ ceph dashboard motd get + +To clear the configured MOTD run:: + + $ ceph dashboard motd clear + +A MOTD with a `info` or `warning` severity can be closed by the user. The +`info` MOTD is not displayed anymore until the local storage cookies are +cleared or a new MOTD with a different severity is displayed. A MOTD with +a 'warning' severity will be displayed again in a new session. diff -Nru ceph-16.2.5/doc/mgr/dashboard.rst ceph-16.2.6/doc/mgr/dashboard.rst --- ceph-16.2.5/doc/mgr/dashboard.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/mgr/dashboard.rst 2021-09-16 14:27:19.000000000 +0000 @@ -376,50 +376,17 @@ Enabling the Object Gateway Management Frontend ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -To use the Object Gateway management functionality of the dashboard, you will -need to provide the login credentials of a user with the ``system`` flag -enabled. If you do not have a ``system`` user already, you must create one:: +When RGW is deployed with cephadm, the RGW credentials used by the +dashboard will be automatically configured. You can also manually force the +credentials to be set up with:: - $ radosgw-admin user create --uid= --display-name= \ - --system + $ ceph dashboard set-rgw-credentials -Take note of the keys ``access_key`` and ``secret_key`` in the output. +This will create an RGW user with uid ``dashboard`` for each realm in +the system. -To obtain the credentials of an existing user via `radosgw-admin`:: +If you've configured a custom 'admin' resource in your RGW admin API, you should set it here also:: - $ radosgw-admin user info --uid= - -In case of having several Object Gateways, you will need the required users' credentials -to connect to each Object Gateway. -Finally, provide these credentials to the dashboard:: - - $ echo -n "{'': '', '': '', ...}" > - $ echo -n "{'': '', '': '', ...}" > - $ ceph dashboard set-rgw-api-access-key -i - $ ceph dashboard set-rgw-api-secret-key -i - -.. note:: - - Legacy way of providing credentials (connect to single Object Gateway):: - - $ echo -n "" > - $ echo -n "" > - -In a simple configuration with a single RGW endpoint, this is all you -have to do to get the Object Gateway management functionality working. The -dashboard will try to automatically determine the host and port -from the Ceph Manager's service map. - -In case of having several Object Gateways, you might want to set -the default one by setting its host and port manually:: - - $ ceph dashboard set-rgw-api-host - $ ceph dashboard set-rgw-api-port - -In addition to the settings mentioned so far, the following settings do also -exist and you may find yourself in the situation that you have to use them:: - - $ ceph dashboard set-rgw-api-scheme # http or https $ ceph dashboard set-rgw-api-admin-resource If you are using a self-signed certificate in your Object Gateway setup, @@ -1314,6 +1281,7 @@ .. include:: dashboard_plugins/feature_toggles.inc.rst .. include:: dashboard_plugins/debug.inc.rst +.. include:: dashboard_plugins/motd.inc.rst Troubleshooting the Dashboard diff -Nru ceph-16.2.5/doc/rados/operations/balancer.rst ceph-16.2.6/doc/rados/operations/balancer.rst --- ceph-16.2.5/doc/rados/operations/balancer.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/rados/operations/balancer.rst 2021-09-16 14:27:19.000000000 +0000 @@ -40,9 +40,37 @@ When the cluster is healthy, the balancer will throttle its changes such that the percentage of PGs that are misplaced (i.e., that need to be moved) is below a threshold of (by default) 5%. The -``max_misplaced`` threshold can be adjusted with:: +``target_max_misplaced_ratio`` threshold can be adjusted with:: - ceph config set mgr mgr/balancer/max_misplaced .07 # 7% + ceph config set mgr target_max_misplaced_ratio .07 # 7% + +Set the number of seconds to sleep in between runs of the automatic balancer:: + + ceph config set mgr mgr/balancer/sleep_interval 60 + +Set the time of day to begin automatic balancing in HHMM format:: + + ceph config set mgr mgr/balancer/begin_time 0000 + +Set the time of day to finish automatic balancing in HHMM format:: + + ceph config set mgr mgr/balancer/end_time 2400 + +Restrict automatic balancing to this day of the week or later. +Uses the same conventions as crontab, 0 or 7 is Sunday, 1 is Monday, and so on:: + + ceph config set mgr mgr/balancer/begin_weekday 0 + +Restrict automatic balancing to this day of the week or earlier. +Uses the same conventions as crontab, 0 or 7 is Sunday, 1 is Monday, and so on:: + + ceph config set mgr mgr/balancer/end_weekday 7 + +Pool IDs to which the automatic balancing will be limited. +The default for this is an empty string, meaning all pools will be balanced. +The numeric pool IDs can be gotten with the :command:`ceph osd pool ls detail` command:: + + ceph config set mgr mgr/balancer/pool_ids 1,2,3 Modes @@ -136,3 +164,4 @@ Assuming the plan is expected to improve the distribution (i.e., it has a lower score than the current cluster state), the user can execute that plan with:: ceph balancer execute + diff -Nru ceph-16.2.5/doc/rados/operations/monitoring.rst ceph-16.2.6/doc/rados/operations/monitoring.rst --- ceph-16.2.5/doc/rados/operations/monitoring.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/rados/operations/monitoring.rst 2021-09-16 14:27:19.000000000 +0000 @@ -410,10 +410,9 @@ to this pool. - **QUOTA OBJECTS:** The number of quota objects. - **QUOTA BYTES:** The number of bytes in the quota objects. -- **DIRTY:** "DIRTY" is meaningful only when cache tiering is in use. If cache - tiering is in use, the "DIRTY" column lists the number of objects in the - cache pool that have been written to the cache pool but have not flushed yet - to the base pool. +- **DIRTY:** The number of objects in the cache pool that have been written to + the cache pool but have not been flushed yet to the base pool. This field is + only available when cache tiering is in use. - **USED COMPR:** amount of space allocated for compressed data (i.e. this includes comrpessed data plus all the allocation, replication and erasure coding overhead). diff -Nru ceph-16.2.5/doc/rados/operations/placement-groups.rst ceph-16.2.6/doc/rados/operations/placement-groups.rst --- ceph-16.2.5/doc/rados/operations/placement-groups.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/rados/operations/placement-groups.rst 2021-09-16 14:27:19.000000000 +0000 @@ -41,10 +41,10 @@ Output will be something like:: - POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO PG_NUM NEW PG_NUM AUTOSCALE - a 12900M 3.0 82431M 0.4695 8 128 warn - c 0 3.0 82431M 0.0000 0.2000 0.9884 1 64 warn - b 0 953.6M 3.0 82431M 0.0347 8 warn + POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE PROFILE + a 12900M 3.0 82431M 0.4695 8 128 warn scale-up + c 0 3.0 82431M 0.0000 0.2000 0.9884 1.0 1 64 warn scale-down + b 0 953.6M 3.0 82431M 0.0347 8 warn scale-down **SIZE** is the amount of data stored in the pool. **TARGET SIZE**, if present, is the amount of data the administrator has specified that @@ -77,6 +77,10 @@ The system uses the larger of the actual ratio and the effective ratio for its calculation. +**BIAS** is used as a multiplier to manually adjust a pool's PG based +on prior information about how much PGs a specific pool is expected +to have. + **PG_NUM** is the current number of PGs for the pool (or the current number of PGs that the pool is working towards, if a ``pg_num`` change is in progress). **NEW PG_NUM**, if present, is what the @@ -84,9 +88,13 @@ always a power of 2, and will only be present if the "ideal" value varies from the current value by more than a factor of 3. -The final column, **AUTOSCALE**, is the pool ``pg_autoscale_mode``, +**AUTOSCALE**, is the pool ``pg_autoscale_mode`` and will be either ``on``, ``off``, or ``warn``. +The final column, **PROFILE** shows the autoscale profile +used by each pool. ``scale-up`` and ``scale-down`` are the +currently available profiles. + Automated scaling ----------------- @@ -113,6 +121,28 @@ to OSDs of class `hdd` will each have optimal PG counts that depend on the number of those respective device types. +The autoscaler uses the `scale-down` profile by default, +where each pool starts out with a full complements of PGs and only scales +down when the usage ratio across the pools is not even. However, it also has +a `scale-up` profile, where it starts out each pool with minimal PGs and scales +up PGs when there is more usage in each pool. + +With only the `scale-down` profile, the autoscaler identifies +any overlapping roots and prevents the pools with such roots +from scaling because overlapping roots can cause problems +with the scaling process. + +To use the `scale-up` profile:: + + ceph osd pool set autoscale-profile scale-up + +To switch back to the default `scale-down` profile:: + + ceph osd pool set autoscale-profile scale-down + +Existing clusters will continue to use the `scale-up` profile. +To use the `scale-down` profile, users will need to set autoscale-profile `scale-down`, +after upgrading to a version of Ceph that provides the `scale-down` feature. .. _specifying_pool_target_size: diff -Nru ceph-16.2.5/doc/radosgw/frontends.rst ceph-16.2.6/doc/radosgw/frontends.rst --- ceph-16.2.5/doc/radosgw/frontends.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/radosgw/frontends.rst 2021-09-16 14:27:19.000000000 +0000 @@ -64,6 +64,38 @@ :Type: String :Default: None +``ssl_options`` + +:Description: Optional colon separated list of ssl context options: + + ``default_workarounds`` Implement various bug workarounds. + + ``no_compression`` Disable compression. + + ``no_sslv2`` Disable SSL v2. + + ``no_sslv3`` Disable SSL v3. + + ``no_tlsv1`` Disable TLS v1. + + ``no_tlsv1_1`` Disable TLS v1.1. + + ``no_tlsv1_2`` Disable TLS v1.2. + + ``single_dh_use`` Always create a new key when using tmp_dh parameters. + +:Type: String +:Default: ``no_sslv2:no_sslv3:no_tlsv1:no_tlsv1_1`` + +``ssl_ciphers`` + +:Description: Optional list of one or more cipher strings separated by colons. + The format of the string is described in openssl's ciphers(1) + manual. + +:Type: String +:Default: None + ``tcp_nodelay`` :Description: If set the socket option will disable Nagle's algorithm on @@ -100,6 +132,7 @@ ======== .. versionadded:: Firefly +.. deprecated:: Pacific The ``civetweb`` frontend uses the Civetweb HTTP library, which is a fork of Mongoose. diff -Nru ceph-16.2.5/doc/radosgw/vault.rst ceph-16.2.6/doc/radosgw/vault.rst --- ceph-16.2.5/doc/radosgw/vault.rst 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/doc/radosgw/vault.rst 2021-09-16 14:27:19.000000000 +0000 @@ -400,6 +400,19 @@ In the example above, the Gateway would only fetch transit encryption keys under ``https://vault-server:8200/v1/transit``. +You can use custom ssl certs to authenticate with vault with help of +following options:: + + rgw crypt vault verify ssl = true + rgw crypt vault ssl cacert = /etc/ceph/vault.ca + rgw crypt vault ssl clientcert = /etc/ceph/vault.crt + rgw crypt vault ssl clientkey = /etc/ceph/vault.key + +where vault.ca is CA certificate and vault.key/vault.crt are private key and ssl +ceritificate generated for RGW to access the vault server. It highly recommended to +set this option true, setting false is very dangerous and need to avoid since this +runs in very secured enviroments. + Transit engine compatibility support ------------------------------------ The transit engine has compatibility support for previous diff -Nru ceph-16.2.5/.github/pull_request_template.md ceph-16.2.6/.github/pull_request_template.md --- ceph-16.2.5/.github/pull_request_template.md 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/.github/pull_request_template.md 2021-09-16 14:27:19.000000000 +0000 @@ -48,6 +48,7 @@ - `jenkins test make check arm64` - `jenkins test submodules` - `jenkins test dashboard` +- `jenkins test dashboard cephadm` - `jenkins test api` - `jenkins test docs` - `jenkins render docs` diff -Nru ceph-16.2.5/make-debs.sh ceph-16.2.6/make-debs.sh --- ceph-16.2.5/make-debs.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/make-debs.sh 2021-09-16 14:27:19.000000000 +0000 @@ -16,9 +16,9 @@ # set -xe +. /etc/os-release base=${1:-/tmp/release} -codename=$(lsb_release -sc) -releasedir=$base/$(lsb_release -si)/WORKDIR +releasedir=$base/$NAME/WORKDIR rm -fr $(dirname $releasedir) mkdir -p $releasedir # @@ -60,7 +60,7 @@ cd ceph-$vers chvers=$(head -1 debian/changelog | perl -ne 's/.*\(//; s/\).*//; print') if [ "$chvers" != "$dvers" ]; then - DEBEMAIL="contact@ceph.com" dch -D $codename --force-distribution -b -v "$dvers" "new version" + DEBEMAIL="contact@ceph.com" dch -D $VERSION_CODENAME --force-distribution -b -v "$dvers" "new version" fi # # create the packages @@ -74,18 +74,18 @@ fi PATH=/usr/lib/ccache:$PATH dpkg-buildpackage $j -uc -us cd ../.. -mkdir -p $codename/conf -cat > $codename/conf/distributions < $VERSION_CODENAME/conf/distributions < $codename/version +echo $dvers > $VERSION_CODENAME/version diff -Nru ceph-16.2.5/make-dist ceph-16.2.6/make-dist --- ceph-16.2.5/make-dist 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/make-dist 2021-09-16 14:27:19.000000000 +0000 @@ -163,7 +163,7 @@ # at the three URLs referenced below (may involve uploading to download.ceph.com) boost_version=1.73.0 download_boost $boost_version 4eb3b8d442b426dc35346235c8733b5ae35ba431690e38c6a8263dce9fcbb402 \ - https://dl.bintray.com/boostorg/release/$boost_version/source \ + https://boostorg.jfrog.io/artifactory/main/release/$boost_version/source \ https://downloads.sourceforge.net/project/boost/boost/$boost_version \ https://download.ceph.com/qa download_liburing 0.7 8e2842cfe947f3a443af301bdd6d034455536c38a455c7a700d0c1ad165a7543 \ diff -Nru ceph-16.2.5/monitoring/grafana/build/Makefile ceph-16.2.6/monitoring/grafana/build/Makefile --- ceph-16.2.5/monitoring/grafana/build/Makefile 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/build/Makefile 2021-09-16 14:27:19.000000000 +0000 @@ -1,33 +1,38 @@ -GRAFANA_VERSION := 6.7.4-1 -PIECHART_VERSION := "1.4.0" -STATUS_PANEL_VERSION := "1.0.9" -DASHBOARD_DIR := "monitoring/grafana/dashboards" +GRAFANA_VERSION ?= 6.7.4-1 +PIECHART_VERSION ?= "1.4.0" +STATUS_PANEL_VERSION ?= "1.0.9" +DASHBOARD_DIR := "../dashboards" DASHBOARD_PROVISIONING := "ceph-dashboard.yml" -IMAGE := "centos:8" -VERSION := "${IMAGE: -1}" +IMAGE := "docker.io/centos:8" PKGMGR := "dnf" -# CONTAINER := $(shell buildah from ${IMAGE}) GF_CONFIG := "/etc/grafana/grafana.ini" -ceph_version := "master" +# clip off "- from the end of GRAFANA_VERSION +CONTAINER_VERSION := $(shell /bin/echo $(GRAFANA_VERSION) | /bin/sed 's/-.*//') + +ARCH ?= x86_64 +ifeq "$(ARCH)" "arm64" + override ARCH := aarch64 +endif + +LOCALTAG=ceph-grafana:$(CONTAINER_VERSION)-$(ARCH) +TAG=ceph/ceph-grafana:$(CONTAINER_VERSION)-$(ARCH) # Build a grafana instance - preconfigured for use within Ceph's dashboard UI -build : fetch_dashboards +build : echo "Creating base container" - $(eval CONTAINER := $(shell buildah from ${IMAGE})) + $(eval CONTAINER := $(shell sudo buildah from ${IMAGE})) # Using upstream grafana build - wget https://dl.grafana.com/oss/release/grafana-${GRAFANA_VERSION}.x86_64.rpm - #wget localhost:8000/grafana-${GRAFANA_VERSION}.x86_64.rpm - #cp grafana-${GRAFANA_VERSION}.x86_64.rpm ${mountpoint}/tmp/. - buildah copy $(CONTAINER) grafana-${GRAFANA_VERSION}.x86_64.rpm /tmp/grafana-${GRAFANA_VERSION}.x86_64.rpm - buildah run $(CONTAINER) ${PKGMGR} install -y --setopt install_weak_deps=false --setopt=tsflags=nodocs /tmp/grafana-${GRAFANA_VERSION}.x86_64.rpm - buildah run $(CONTAINER) ${PKGMGR} clean all - buildah run $(CONTAINER) rm -f /tmp/grafana*.rpm - buildah run $(CONTAINER) grafana-cli plugins install grafana-piechart-panel ${PIECHART_VERSION} - buildah run $(CONTAINER) grafana-cli plugins install vonage-status-panel ${STATUS_PANEL_VERSION} - buildah run $(CONTAINER) mkdir -p /etc/grafana/dashboards/ceph-dashboard - buildah copy $(CONTAINER) jsonfiles/*.json /etc/grafana/dashboards/ceph-dashboard + curl -fLO https://dl.grafana.com/oss/release/grafana-${GRAFANA_VERSION}.${ARCH}.rpm + sudo buildah copy $(CONTAINER) grafana-${GRAFANA_VERSION}.${ARCH}.rpm /tmp/grafana-${GRAFANA_VERSION}.${ARCH}.rpm + sudo buildah run $(CONTAINER) ${PKGMGR} install -y --setopt install_weak_deps=false --setopt=tsflags=nodocs /tmp/grafana-${GRAFANA_VERSION}.${ARCH}.rpm + sudo buildah run $(CONTAINER) ${PKGMGR} clean all + sudo buildah run $(CONTAINER) rm -f /tmp/grafana*.rpm + sudo buildah run $(CONTAINER) grafana-cli plugins install grafana-piechart-panel ${PIECHART_VERSION} + sudo buildah run $(CONTAINER) grafana-cli plugins install vonage-status-panel ${STATUS_PANEL_VERSION} + sudo buildah run $(CONTAINER) mkdir -p /etc/grafana/dashboards/ceph-dashboard + sudo buildah copy $(CONTAINER) ${DASHBOARD_DIR}/*.json /etc/grafana/dashboards/ceph-dashboard @/bin/echo -e "\ apiVersion: 1 \\n\ @@ -43,55 +48,49 @@ path: '/etc/grafana/dashboards/ceph-dashboard'" >> ${DASHBOARD_PROVISIONING} - buildah copy $(CONTAINER) ${DASHBOARD_PROVISIONING} /etc/grafana/provisioning/dashboards/${DASHBOARD_PROVISIONING} + sudo buildah copy $(CONTAINER) ${DASHBOARD_PROVISIONING} /etc/grafana/provisioning/dashboards/${DASHBOARD_PROVISIONING} # expose tcp/3000 for grafana - buildah config --port 3000 $(CONTAINER) + sudo buildah config --port 3000 $(CONTAINER) # set working dir - buildah config --workingdir /usr/share/grafana $(CONTAINER) + sudo buildah config --workingdir /usr/share/grafana $(CONTAINER) # set environment overrides from the default locations in /usr/share - buildah config --env GF_PATHS_LOGS="/var/log/grafana" $(CONTAINER) - buildah config --env GF_PATHS_PLUGINS="/var/lib/grafana/plugins" $(CONTAINER) - buildah config --env GF_PATHS_PROVISIONING="/etc/grafana/provisioning" $(CONTAINER) - buildah config --env GF_PATHS_DATA="/var/lib/grafana" $(CONTAINER) + sudo buildah config --env GF_PATHS_LOGS="/var/log/grafana" $(CONTAINER) + sudo buildah config --env GF_PATHS_PLUGINS="/var/lib/grafana/plugins" $(CONTAINER) + sudo buildah config --env GF_PATHS_PROVISIONING="/etc/grafana/provisioning" $(CONTAINER) + sudo buildah config --env GF_PATHS_DATA="/var/lib/grafana" $(CONTAINER) # entrypoint - buildah config --entrypoint "grafana-server --config=${GF_CONFIG}" $(CONTAINER) + sudo buildah config --entrypoint "grafana-server --config=${GF_CONFIG}" $(CONTAINER) # finalize - buildah config --label maintainer="Paul Cuzner " $(CONTAINER) - buildah config --label description="Ceph Grafana Container" $(CONTAINER) - buildah config --label summary="Grafana Container configured for Ceph mgr/dashboard integration" $(CONTAINER) - buildah commit --format docker --squash $(CONTAINER) ceph-grafana:${ceph_version} - buildah tag ceph-grafana:${ceph_version} ceph/ceph-grafana:${ceph_version} - - -fetch_dashboards: clean - wget -O - https://api.github.com/repos/ceph/ceph/contents/${DASHBOARD_DIR}?ref=${ceph_version} | jq '.[].download_url' > dashboards - - # drop quotes from the list and pick out only json files - sed -i 's/\"//g' dashboards - sed -i '/\.json/!d' dashboards - mkdir jsonfiles - while read -r line; do \ - wget "$$line" -P jsonfiles; \ - done < dashboards - -clean : - rm -f dashboards - rm -fr jsonfiles - rm -f grafana-*.rpm* + sudo buildah config --label maintainer="Paul Cuzner " $(CONTAINER) + sudo buildah config --label description="Ceph Grafana Container" $(CONTAINER) + sudo buildah config --label summary="Grafana Container configured for Ceph mgr/dashboard integration" $(CONTAINER) + sudo buildah commit --format docker --squash $(CONTAINER) $(LOCALTAG) + +push: + # this transition-through-oci image is a workaround for + # https://github.com/containers/buildah/issues/3253 and + # can be removed when that is fixed and released. The + # --format v2s2 on push is to convert oci back to docker format. + sudo podman push $(LOCALTAG) --format=oci dir://tmp/oci-image + sudo podman pull dir://tmp/oci-image + sudo rm -rf /tmp/oci-image + sudo podman tag localhost/tmp/oci-image docker.io/${TAG} + sudo podman tag localhost/tmp/oci-image quay.io/${TAG} + # sudo podman has issues with auth.json; just override it + sudo podman login --authfile=auth.json -u ${DOCKER_HUB_USERNAME} -p ${DOCKER_HUB_PASSWORD} docker.io + sudo podman login --authfile=auth.json -u $(CONTAINER_REPO_USERNAME) -p $(CONTAINER_REPO_PASSWORD) quay.io + sudo podman push --authfile=auth.json --format v2s2 docker.io/${TAG} + sudo podman push --authfile=auth.json --format v2s2 quay.io/${TAG} + +clean: + sudo podman rmi ${LOCALTAG} || true + sudo podman rmi docker.io/${TAG} || true + sudo podman rmi quay.io/${TAG} || true + sudo podman rmi localhost/tmp/oci-image || true + rm -f grafana-*.rpm* auth.json rm -f ${DASHBOARD_PROVISIONING} - - -nautilus : - $(MAKE) ceph_version="nautilus" build -octopus : - $(MAKE) ceph_version="octopus" build -master : - $(MAKE) ceph_version="master" build - -all : nautilus octopus master -.PHONY : all diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/ceph-cluster.json ceph-16.2.6/monitoring/grafana/dashboards/ceph-cluster.json --- ceph-16.2.5/monitoring/grafana/dashboards/ceph-cluster.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/ceph-cluster.json 2021-09-16 14:27:19.000000000 +0000 @@ -107,8 +107,9 @@ "tableColumn": "", "targets": [ { - "expr": "ceph_health_status{instance=~'$instance'}", + "expr": "ceph_health_status", "format": "time_series", + "instant": true, "interval": "$interval", "intervalFactor": 1, "refId": "A", @@ -174,7 +175,7 @@ "displayAliasType": "Always", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "count(ceph_osd_metadata{instance=~\"$instance\"})", + "expr": "count(ceph_osd_metadata)", "format": "time_series", "intervalFactor": 1, "legendFormat": "All", @@ -189,7 +190,7 @@ "displayAliasType": "Always", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "sum(ceph_osds_in{instance=~\"$instance\"})", + "expr": "sum(ceph_osds_in)", "format": "time_series", "intervalFactor": 1, "legendFormat": "In", @@ -204,7 +205,7 @@ "displayAliasType": "Warning / Critical", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "sum(ceph_osd_in{instance=~\"$instance\"} == bool 0)", + "expr": "sum(ceph_osd_in == bool 0)", "format": "time_series", "interval": "", "intervalFactor": 1, @@ -221,7 +222,7 @@ "displayAliasType": "Always", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "sum(ceph_osd_up{instance=~\"$instance\"})", + "expr": "sum(ceph_osd_up)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Up", @@ -237,7 +238,7 @@ "displayAliasType": "Warning / Critical", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "sum(ceph_osd_up{instance=~\"$instance\"} == bool 0)", + "expr": "sum(ceph_osd_up == bool 0)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Down", @@ -263,7 +264,7 @@ "decimals": 2, "format": "percentunit", "gauge": { - "maxValue": 100, + "maxValue": 1, "minValue": 0, "show": true, "thresholdLabels": false, @@ -312,14 +313,14 @@ "tableColumn": "", "targets": [ { - "expr": "sum(ceph_osd_stat_bytes_used{instance=~\"$instance\"})/sum(ceph_osd_stat_bytes{instance=~\"$instance\"})", + "expr": "sum(ceph_osd_stat_bytes_used)/sum(ceph_osd_stat_bytes)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Used", "refId": "A" } ], - "thresholds": "70,80", + "thresholds": "0.7,0.8", "title": "Capacity used", "type": "singlestat", "valueFontSize": "80%", @@ -530,28 +531,28 @@ "steppedLine": false, "targets": [ { - "expr": "quantile(0.95, ceph_osd_apply_latency_ms{instance=~\"$instance\"})", + "expr": "quantile(0.95, ceph_osd_apply_latency_ms)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Apply Latency P_95", "refId": "A" }, { - "expr": "quantile(0.95, ceph_osd_commit_latency_ms{instance=~\"$instance\"})", + "expr": "quantile(0.95, ceph_osd_commit_latency_ms)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Commit Latency P_95", "refId": "B" }, { - "expr": "avg(ceph_osd_apply_latency_ms{instance=~\"$instance\"})", + "expr": "avg(ceph_osd_apply_latency_ms)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Avg Apply Latency", "refId": "C" }, { - "expr": "avg(ceph_osd_commit_latency_ms{instance=~\"$instance\"})", + "expr": "avg(ceph_osd_commit_latency_ms)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Avg Commit Latency", @@ -629,7 +630,7 @@ "displayAliasType": "Always", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "sum(ceph_mon_quorum_status{instance=~\"$instance\"})", + "expr": "sum(ceph_mon_quorum_status)", "format": "time_series", "interval": "", "intervalFactor": 1, @@ -646,7 +647,7 @@ "displayAliasType": "Always", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "count(ceph_mon_quorum_status{instance=~\"$instance\"})", + "expr": "count(ceph_mon_quorum_status)", "format": "time_series", "intervalFactor": 1, "legendFormat": "Total", @@ -663,7 +664,7 @@ "displayAliasType": "Warning / Critical", "displayType": "Annotation", "displayValueWithAlias": "Never", - "expr": "count(ceph_mon_quorum_status{instance=~\"$instance\"}) / sum(ceph_mon_quorum_status{instance=~\"$instance\"})", + "expr": "count(ceph_mon_quorum_status) / sum(ceph_mon_quorum_status)", "format": "time_series", "intervalFactor": 1, "legendFormat": "MONs out of Quorum", @@ -710,7 +711,7 @@ "displayAliasType": "Always", "displayType": "Regular", "displayValueWithAlias": "When Alias Displayed", - "expr": "ceph_mds_server_handle_client_session{instance=~\"$instance\"}", + "expr": "ceph_mds_server_handle_client_session", "format": "time_series", "intervalFactor": 1, "legendFormat": "Clients", @@ -764,14 +765,14 @@ "steppedLine": false, "targets": [ { - "expr": "sum(irate(ceph_osd_op_w_in_bytes{instance=~\"$instance\"}[1m]))", + "expr": "sum(irate(ceph_osd_op_w_in_bytes[1m]))", "format": "time_series", "intervalFactor": 1, "legendFormat": "Writes", "refId": "A" }, { - "expr": "sum(irate(ceph_osd_op_r_out_bytes{instance=~\"$instance\"}[1m]))", + "expr": "sum(irate(ceph_osd_op_r_out_bytes[1m]))", "format": "time_series", "intervalFactor": 1, "legendFormat": "Reads", @@ -851,7 +852,7 @@ "steppedLine": false, "targets": [ { - "expr": "sum(deriv(ceph_pool_stored{instance=~\"$instance\"}[1m]))", + "expr": "sum(deriv(ceph_pool_stored[1m]))", "format": "time_series", "intervalFactor": 1, "refId": "A" @@ -924,7 +925,7 @@ "span": 12, "targets": [ { - "expr": "ceph_osd_stat_bytes_used{instance=~'$instance'} / ceph_osd_stat_bytes{instance=~'$instance'}", + "expr": "ceph_osd_stat_bytes_used / ceph_osd_stat_bytes", "format": "time_series", "interval": "1m", "intervalFactor": 1, @@ -946,7 +947,7 @@ "xBucketNumber": null, "xBucketSize": "", "yAxis": { - "decimals": null, + "decimals": 2, "format": "percentunit", "logBase": 1, "max": null, @@ -986,7 +987,7 @@ "links": [], "targets": [ { - "expr": "ceph_osd_numpg{instance=~\"$instance\"}", + "expr": "ceph_osd_numpg", "format": "time_series", "intervalFactor": 1, "legendFormat": "#PGs", @@ -1190,29 +1191,6 @@ "query": "1m,10m,30m,1h,6h,12h,1d,7d,14d,30d", "refresh": 2, "type": "interval" - }, - { - "allFormat": "glob", - "allValue": null, - "current": {}, - "datasource": "$datasource", - "hide": 0, - "hideLabel": false, - "includeAll": true, - "label": "Exporter Instance", - "multi": false, - "multiFormat": "glob", - "name": "instance", - "options": [], - "query": "label_values(ceph_health_status, instance)", - "refresh": 1, - "regex": "", - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false } ] }, @@ -1245,7 +1223,7 @@ "30d" ] }, - "timezone": "browser", + "timezone": "", "title": "Ceph - Cluster", "version": 13 } diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/CMakeLists.txt ceph-16.2.6/monitoring/grafana/dashboards/CMakeLists.txt --- ceph-16.2.5/monitoring/grafana/dashboards/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -1,8 +1,34 @@ set(CEPH_GRAFANA_DASHBOARDS_DIR "${CMAKE_INSTALL_SYSCONFDIR}/grafana/dashboards/ceph-dashboard" CACHE PATH "Location for grafana dashboards") - -FILE(GLOB CEPH_GRAFANA_DASHBOARDS "*.json") - +file(GLOB CEPH_GRAFANA_DASHBOARDS "*.json") install(FILES ${CEPH_GRAFANA_DASHBOARDS} DESTINATION ${CEPH_GRAFANA_DASHBOARDS_DIR}) + +set(CEPH_BUILD_VIRTUALENV $ENV{TMPDIR}) +if(NOT CEPH_BUILD_VIRTUALENV) + set(CEPH_BUILD_VIRTUALENV ${CMAKE_BINARY_DIR}) +endif() + +if(WITH_GRAFANA) + include(AddCephTest) + add_tox_test(grafana TOX_ENVS grafonnet-check) + set(ver 0.1.0) + set(name grafonnet-lib) + include(ExternalProject) + ExternalProject_Add(${name} + URL https://github.com/grafana/${name}/archive/v${ver}/${name}-${ver}.tar.gz + URL_MD5 0798752ed40864fa8b3db40a3c970642 + BUILD_COMMAND "" + CONFIGURE_COMMAND "" + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL ON) + add_dependencies(tests + ${name}) + ExternalProject_Get_Property(${name} SOURCE_DIR) + set_property( + TEST run-tox-grafana + APPEND + PROPERTY ENVIRONMENT + GRAFONNET_PATH=${SOURCE_DIR}/grafonnet) +endif() diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/host-details.json ceph-16.2.6/monitoring/grafana/dashboards/host-details.json --- ceph-16.2.5/monitoring/grafana/dashboards/host-details.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/host-details.json 2021-09-16 14:27:19.000000000 +0000 @@ -1208,7 +1208,7 @@ "30d" ] }, - "timezone": "browser", + "timezone": "", "title": "Host Details", "uid": "rtOg0AiWz", "version": 4 diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/jsonnet/grafana_dashboards.jsonnet ceph-16.2.6/monitoring/grafana/dashboards/jsonnet/grafana_dashboards.jsonnet --- ceph-16.2.5/monitoring/grafana/dashboards/jsonnet/grafana_dashboards.jsonnet 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/jsonnet/grafana_dashboards.jsonnet 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,54 @@ +local g = import 'grafana.libsonnet'; + +local dashboardSchema(title, uid, time_from, refresh, schemaVersion, tags,timezone, timepicker) = + g.dashboard.new(title=title, uid=uid, time_from=time_from, refresh=refresh, schemaVersion=schemaVersion, tags=tags, timezone=timezone, timepicker=timepicker); + +local graphPanelSchema(title, nullPointMode, stack, formatY1, formatY2, labelY1, labelY2, min, fill, datasource) = + g.graphPanel.new(title=title, nullPointMode=nullPointMode, stack=stack, formatY1=formatY1, formatY2=formatY2, labelY1=labelY1, labelY2=labelY2, min=min, fill=fill, datasource=datasource); + +local addTargetSchema(expr, intervalFactor, format, legendFormat) = + g.prometheus.target(expr=expr, intervalFactor=intervalFactor, format=format, legendFormat=legendFormat); + +local addTemplateSchema(name, datasource, query, refresh, hide, includeAll, sort) = + g.template.new(name=name, datasource=datasource, query=query, refresh=refresh, hide=hide, includeAll=includeAll, sort=sort); + +local addAnnotationSchema(builtIn, datasource, enable, hide, iconColor, name, type) = + g.annotation.datasource(builtIn=builtIn, datasource=datasource, enable=enable, hide=hide, iconColor=iconColor, name=name, type=type); + +{ + "radosgw-sync-overview.json": + local RgwSyncOverviewPanel(title, formatY1, labelY1, rgwMetric, x, y, w, h) = + graphPanelSchema(title, 'null as zero', true, formatY1, 'short', labelY1, null, 0, 1, '$datasource') + .addTargets( + [addTargetSchema('sum by (source_zone) (rate(%s[30s]))' % rgwMetric, 1, 'time_series', '{{source_zone}}')]) + {gridPos: {x: x, y: y, w: w, h: h}}; + + dashboardSchema( + 'RGW Sync Overview', 'rgw-sync-overview', 'now-1h', '15s', 16, ["overview"], '', {refresh_intervals:['5s','10s','15s','30s','1m','5m','15m','30m','1h','2h','1d'],time_options:['5m','15m','1h','6h','12h','24h','2d','7d','30d']} + ) + .addAnnotation( + addAnnotationSchema( + 1, '-- Grafana --', true, true, 'rgba(0, 211, 255, 1)', 'Annotations & Alerts', 'dashboard') + ) + .addRequired( + type='grafana', id='grafana', name='Grafana', version='5.0.0' + ) + .addRequired( + type='panel', id='graph', name='Graph', version='5.0.0' + ) + .addTemplate( + addTemplateSchema('rgw_servers', '$datasource', 'prometehus', 1, 2, true, 1) + ) + .addTemplate( + g.template.datasource('datasource', 'prometheus', 'default', label='Data Source') + ) + .addPanels([ + RgwSyncOverviewPanel( + 'Replication (throughput) from Source Zone', 'Bps', null, 'ceph_data_sync_from_zone_fetch_bytes_sum', 0, 0, 8, 7), + RgwSyncOverviewPanel( + 'Replication (objects) from Source Zone', 'short', 'Objects/s', 'ceph_data_sync_from_zone_fetch_bytes_count', 8, 0, 8, 7), + RgwSyncOverviewPanel( + 'Polling Request Latency from Source Zone', 'ms', null, 'ceph_data_sync_from_zone_poll_latency_sum', 16, 0, 8, 7), + RgwSyncOverviewPanel( + 'Unsuccessful Object Replications from Source Zone', 'short', 'Count/s', 'ceph_data_sync_from_zone_fetch_errors', 0, 7, 8, 7) + ]) +} diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/osd-device-details.json ceph-16.2.6/monitoring/grafana/dashboards/osd-device-details.json --- ceph-16.2.5/monitoring/grafana/dashboards/osd-device-details.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/osd-device-details.json 2021-09-16 14:27:19.000000000 +0000 @@ -423,7 +423,7 @@ }, "yaxes": [ { - "format": "ms", + "format": "s", "label": "Read (-) / Write (+)", "logBase": 1, "max": null, diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/pool-detail.json ceph-16.2.6/monitoring/grafana/dashboards/pool-detail.json --- ceph-16.2.5/monitoring/grafana/dashboards/pool-detail.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/pool-detail.json 2021-09-16 14:27:19.000000000 +0000 @@ -658,7 +658,7 @@ "30d" ] }, - "timezone": "browser", + "timezone": "", "title": "Ceph Pool Details", "uid": "-xyV8KCiz", "version": 1 diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/pool-overview.json ceph-16.2.6/monitoring/grafana/dashboards/pool-overview.json --- ceph-16.2.5/monitoring/grafana/dashboards/pool-overview.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/pool-overview.json 2021-09-16 14:27:19.000000000 +0000 @@ -1554,7 +1554,7 @@ "30d" ] }, - "timezone": "browser", + "timezone": "", "title": "Ceph Pools Overview", "uid": "z99hzWtmk", "variables": { diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/radosgw-sync-overview.json ceph-16.2.6/monitoring/grafana/dashboards/radosgw-sync-overview.json --- ceph-16.2.5/monitoring/grafana/dashboards/radosgw-sync-overview.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/radosgw-sync-overview.json 2021-09-16 14:27:19.000000000 +0000 @@ -1,440 +1,455 @@ { - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "5.0.0" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "5.0.0" - } - ], - "annotations": { - "list": [ + "__inputs": [ ], + "__requires": [ { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": false, - "gnetId": null, - "graphTooltip": 0, - "id": null, - "iteration": 1534386107523, - "links": [], - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "fill": 1, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 0 - }, - "id": 1, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_fetch_bytes_sum[30s]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{source_zone}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Replication (throughput) from Source Zone", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "unit": "bytes", - "format": "Bps", - "decimals": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "fill": 1, - "gridPos": { - "h": 7, - "w": 7.4, - "x": 8.3, - "y": 0 - }, - "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_fetch_bytes_count[30s]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{source_zone}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Replication (objects) from Source Zone", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "decimals": null, - "label": "Objects/s", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "fill": 1, - "gridPos": { - "h": 7, - "w": 8, - "x": 16, - "y": 0 - }, - "id": 3, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false + "id": "grafana", + "name": "Grafana", + "type": "grafana", + "version": "5.0.0" }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_poll_latency_sum[30s]) * 1000)", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{source_zone}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Polling Request Latency from Source Zone", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "unit": "s", - "format": "ms", - "decimals": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } + { + "id": "graph", + "name": "Graph", + "type": "panel", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "showIn": 0, + "tags": [ ], + "type": "dashboard" + } ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$datasource", - "fill": 1, - "gridPos": { - "h": 7, - "w": 8, - "x": 0, - "y": 7 - }, - "id": 4, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": true, - "steppedLine": false, - "targets": [ - { - "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_fetch_errors[30s]))", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "{{source_zone}}", - "refId": "A" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Unsuccessful Object Replications from Source Zone", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" + }, + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "hideControls": false, + "id": null, + "links": [ ], + "panels": [ + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 2, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_fetch_bytes_sum[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{source_zone}}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Replication (throughput) from Source Zone", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] + { + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 3, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_fetch_bytes_count[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{source_zone}}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Replication (objects) from Source Zone", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "format": "short", + "label": "Objects/s", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] }, - "yaxes": [ - { - "format": "short", - "decimals": null, - "label": "Count/s", - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": false - } - ] - } - ], - "refresh": "15s", - "schemaVersion": 16, - "style": "dark", - "tags": [ - "overview" - ], - "templating": { - "list": [ { - "allValue": null, - "current": {}, - "datasource": "$datasource", - "hide": 2, - "includeAll": true, - "label": null, - "multi": false, - "name": "rgw_servers", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 4, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_poll_latency_sum[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{source_zone}}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Polling Request Latency from Source Zone", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] }, { - "current": { - "tags": [], - "text": "default", - "value": "default" - }, - "hide": 0, - "label": "Data Source", - "name": "datasource", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "type": "datasource" + "aliasColors": { }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$datasource", + "fill": 1, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 7 + }, + "id": 5, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "sideWidth": null, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [ ], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "repeat": null, + "seriesOverrides": [ ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "expr": "sum by (source_zone) (rate(ceph_data_sync_from_zone_fetch_errors[30s]))", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{source_zone}}", + "refId": "A" + } + ], + "thresholds": [ ], + "timeFrom": null, + "timeShift": null, + "title": "Unsuccessful Object Replications from Source Zone", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [ ] + }, + "yaxes": [ + { + "format": "short", + "label": "Count/s", + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ] } - ] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "15s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "RGW Sync Overview", - "uid": "rgw-sync-overview", - "version": 2 + ], + "refresh": "15s", + "rows": [ ], + "schemaVersion": 16, + "style": "dark", + "tags": [ + "overview" + ], + "templating": { + "list": [ + { + "allValue": null, + "current": { }, + "datasource": "$datasource", + "hide": 2, + "includeAll": true, + "label": null, + "multi": false, + "name": "rgw_servers", + "options": [ ], + "query": "prometehus", + "refresh": 1, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [ ], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "current": { + "text": "default", + "value": "default" + }, + "hide": 0, + "label": "Data Source", + "name": "datasource", + "options": [ ], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "15s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "RGW Sync Overview", + "uid": "rgw-sync-overview", + "version": 0 } diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/rbd-details.json ceph-16.2.6/monitoring/grafana/dashboards/rbd-details.json --- ceph-16.2.5/monitoring/grafana/dashboards/rbd-details.json 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/rbd-details.json 2021-09-16 14:27:19.000000000 +0000 @@ -1,409 +1,409 @@ -{ - "__inputs": [], - "__requires": [ - { - "type": "grafana", - "id": "grafana", - "name": "Grafana", - "version": "5.3.3" - }, - { - "type": "panel", - "id": "graph", - "name": "Graph", - "version": "5.0.0" - } - ], - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "description": "Detailed Performance of RBD Images (IOPS/Throughput/Latency)", - "editable": false, - "gnetId": null, - "graphTooltip": 0, - "id": null, - "iteration": 1584428820779, - "links": [], - "panels": [ - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$Datasource", - "fill": 1, - "gridPos": { - "h": 9, - "w": 8, - "x": 0, - "y": 0 - }, - "id": 6, - "legend": { - "avg": false, - "current": false, - "hideEmpty": false, - "hideZero": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "irate(ceph_rbd_write_ops{pool=\"$Pool\", image=\"$Image\"}[30s])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Write", - "refId": "A" - }, - { - "expr": "irate(ceph_rbd_read_ops{pool=\"$Pool\", image=\"$Image\"}[30s])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Read", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "IOPS", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "iops", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "iops", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": true, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$Datasource", - "fill": 1, - "gridPos": { - "h": 9, - "w": 8, - "x": 8, - "y": 0 - }, - "id": 4, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "irate(ceph_rbd_write_bytes{pool=\"$Pool\", image=\"$Image\"}[30s])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Write", - "refId": "A" - }, - { - "expr": "irate(ceph_rbd_read_bytes{pool=\"$Pool\", image=\"$Image\"}[30s])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Read", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Throughput", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "Bps", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": true, - "alignLevel": null - } - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "$Datasource", - "fill": 1, - "gridPos": { - "h": 9, - "w": 8, - "x": 16, - "y": 0 - }, - "id": 2, - "legend": { - "avg": false, - "current": false, - "max": false, - "min": false, - "show": true, - "total": false, - "values": false - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null as zero", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "expr": "irate(ceph_rbd_write_latency_sum{pool=\"$Pool\", image=\"$Image\"}[30s]) / irate(ceph_rbd_write_latency_count{pool=\"$Pool\", image=\"$Image\"}[30s])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Write", - "refId": "A" - }, - { - "expr": "irate(ceph_rbd_read_latency_sum{pool=\"$Pool\", image=\"$Image\"}[30s]) / irate(ceph_rbd_read_latency_count{pool=\"$Pool\", image=\"$Image\"}[30s])", - "format": "time_series", - "intervalFactor": 1, - "legendFormat": "Read", - "refId": "B" - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Average Latency", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": "0", - "show": true - }, - { - "format": "ns", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ], - "yaxis": { - "align": true, - "alignLevel": null - } - } - ], - "refresh": false, - "schemaVersion": 16, - "style": "dark", - "tags": [], - "templating": { - "list": [ - { - "current": {}, - "hide": 0, - "label": null, - "name": "Datasource", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "type": "datasource" - }, - { - "allValue": null, - "current": {}, - "datasource": "$Datasource", - "hide": 0, - "includeAll": false, - "label": null, - "multi": false, - "name": "Pool", - "options": [], - "query": "label_values(pool)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - }, - { - "allValue": null, - "current": {}, - "datasource": "$Datasource", - "hide": 0, - "includeAll": false, - "label": null, - "multi": false, - "name": "Image", - "options": [], - "query": "label_values(image)", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "sort": 0, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "", - "type": "query", - "useTags": false - } - ] - }, - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "timezone": "", - "title": "RBD Details", - "uid": "YhCYGcuZz", - "version": 7 -} \ No newline at end of file +{ + "__inputs": [], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "5.3.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "5.0.0" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "Detailed Performance of RBD Images (IOPS/Throughput/Latency)", + "editable": false, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1584428820779, + "links": [], + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$Datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 6, + "legend": { + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(ceph_rbd_write_ops{pool=\"$Pool\", image=\"$Image\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write", + "refId": "A" + }, + { + "expr": "irate(ceph_rbd_read_ops{pool=\"$Pool\", image=\"$Image\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Read", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "IOPS", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "iops", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "iops", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": true, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$Datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 4, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(ceph_rbd_write_bytes{pool=\"$Pool\", image=\"$Image\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write", + "refId": "A" + }, + { + "expr": "irate(ceph_rbd_read_bytes{pool=\"$Pool\", image=\"$Image\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Read", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Throughput", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "Bps", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": true, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$Datasource", + "fill": 1, + "gridPos": { + "h": 9, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null as zero", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(ceph_rbd_write_latency_sum{pool=\"$Pool\", image=\"$Image\"}[30s]) / irate(ceph_rbd_write_latency_count{pool=\"$Pool\", image=\"$Image\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Write", + "refId": "A" + }, + { + "expr": "irate(ceph_rbd_read_latency_sum{pool=\"$Pool\", image=\"$Image\"}[30s]) / irate(ceph_rbd_read_latency_count{pool=\"$Pool\", image=\"$Image\"}[30s])", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Read", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Average Latency", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ns", + "label": null, + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "ns", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": true, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": {}, + "hide": 0, + "label": null, + "name": "Datasource", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": null, + "current": {}, + "datasource": "$Datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "Pool", + "options": [], + "query": "label_values(pool)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "current": {}, + "datasource": "$Datasource", + "hide": 0, + "includeAll": false, + "label": null, + "multi": false, + "name": "Image", + "options": [], + "query": "label_values(image)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "RBD Details", + "uid": "YhCYGcuZz", + "version": 7 +} diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/requirements-grafonnet.txt ceph-16.2.6/monitoring/grafana/dashboards/requirements-grafonnet.txt --- ceph-16.2.5/monitoring/grafana/dashboards/requirements-grafonnet.txt 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/requirements-grafonnet.txt 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1 @@ +jsondiff diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/test-jsonnet.sh ceph-16.2.6/monitoring/grafana/dashboards/test-jsonnet.sh --- ceph-16.2.5/monitoring/grafana/dashboards/test-jsonnet.sh 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/test-jsonnet.sh 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -e +TEMPDIR=`mktemp -d` +BASEDIR=$(dirname "$0") + +JSONNET_PATH="${GRAFONNET_PATH}" jsonnet -m ${TEMPDIR} $BASEDIR/jsonnet/grafana_dashboards.jsonnet + +truncate -s 0 ${TEMPDIR}/json_difference.log +for json_files in $BASEDIR/*.json +do + JSON_FILE_NAME=$(basename $json_files) + for generated_files in ${TEMPDIR}/*.json + do + GENERATED_FILE_NAME=$(basename $generated_files) + if [ $JSON_FILE_NAME == $GENERATED_FILE_NAME ]; then + jsondiff --indent 2 $generated_files $json_files | tee -a ${TEMPDIR}/json_difference.log + fi + done +done + +if [[ $(wc -l < ${TEMPDIR}/json_difference.log) -eq 0 ]] +then + rm -rf ${TEMPDIR} + echo "Congratulations! Grafonnet Check Passed" +else + rm -rf ${TEMPDIR} + echo "Grafonnet Check Failed, failed comparing generated file with existing" + exit 1 +fi diff -Nru ceph-16.2.5/monitoring/grafana/dashboards/tox.ini ceph-16.2.6/monitoring/grafana/dashboards/tox.ini --- ceph-16.2.5/monitoring/grafana/dashboards/tox.ini 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/monitoring/grafana/dashboards/tox.ini 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,22 @@ +[tox] +envlist = grafonnet-{check,fix} +skipsdist = true + +[grafonnet] +deps = + -rrequirements-grafonnet.txt + +[testenv:grafonnet-{check,fix}] +basepython = python3 +whitelist_externals = + jsonnet + bash +description = + check: Ensure that auto-generated grafana dashboard files matches the current version + fix: generate dashboard json files from jsonnet file with latest changes +deps = + {[grafonnet]deps} +passenv = GRAFONNET_PATH +commands = + check: bash test-jsonnet.sh + fix: jsonnet -m . jsonnet/grafana_dashboards.jsonnet diff -Nru ceph-16.2.5/PendingReleaseNotes ceph-16.2.6/PendingReleaseNotes --- ceph-16.2.5/PendingReleaseNotes 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/PendingReleaseNotes 2021-09-16 14:27:19.000000000 +0000 @@ -1,5 +1,13 @@ >=17.0.0 +* `ceph-mgr-modules-core` debian package does not recommend `ceph-mgr-rook` + anymore. As the latter depends on `python3-numpy` which cannot be imported in + different Python sub-interpreters multi-times if the version of + `python3-numpy` is older than 1.19. Since `apt-get` installs the `Recommends` + packages by default, `ceph-mgr-rook` was always installed along with + `ceph-mgr` debian package as an indirect dependency. If your workflow depends + on this behavior, you might want to install `ceph-mgr-rook` separately. + * A new library is available, libcephsqlite. It provides a SQLite Virtual File System (VFS) on top of RADOS. The database and journals are striped over RADOS across multiple objects for virtually unlimited scaling and throughput @@ -9,6 +17,28 @@ that were storing state in RADOS omap, especially without striping which limits scalability. +* MDS upgrades no longer require stopping all standby MDS daemons before + upgrading the sole active MDS for a file system. + +* RGW: It is possible to specify ssl options and ciphers for beast frontend now. + The default ssl options setting is "no_sslv2:no_sslv3:no_tlsv1:no_tlsv1_1". + If you want to return back the old behavior add 'ssl_options=' (empty) to + ``rgw frontends`` configuration. + +* fs: A file system can be created with a specific ID ("fscid"). This is useful + in certain recovery scenarios, e.g., monitor database lost and rebuilt, and + the restored file system is expected to have the same ID as before. + +>=16.2.6 +-------- + +* MGR: The pg_autoscaler has a new default 'scale-down' profile which provides more + performance from the start for new pools (for newly created clusters). + Existing clusters will retain the old behavior, now called the 'scale-up' profile. + For more details, see: + + https://docs.ceph.com/en/latest/rados/operations/placement-groups/ + >=16.0.0 -------- @@ -42,12 +72,6 @@ deprecated and will be removed in a future release. Please use ``nfs cluster rm`` and ``nfs export rm`` instead. -* mgr-pg_autoscaler: Autoscaler will now start out by scaling each - pool to have a full complements of pgs from the start and will only - decrease it when other pools need more pgs due to increased usage. - This improves out of the box performance of Ceph by allowing more PGs - to be created for a given pool. - * CephFS: Disabling allow_standby_replay on a file system will also stop all standby-replay daemons for that file system. @@ -159,6 +183,8 @@ CentOS 7.6 and later. To enable older clients, set ``cephx_require_version`` and ``cephx_service_require_version`` config options to 1. +* rgw: The Civetweb frontend is now deprecated and will be removed in Quincy. + >=15.0.0 -------- diff -Nru ceph-16.2.5/qa/distros/podman/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/distros/podman/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/distros/podman/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/distros/podman/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/distros/podman/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/distros/podman/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/distros/podman/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/distros/podman/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/distros/podman/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/distros/podman/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/distros/podman/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/distros/podman/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/rgw/ignore-pg-availability.yaml ceph-16.2.6/qa/rgw/ignore-pg-availability.yaml --- ceph-16.2.5/qa/rgw/ignore-pg-availability.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/rgw/ignore-pg-availability.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +# https://tracker.ceph.com/issues/45802 +overrides: + ceph: + log-ignorelist: + - \(PG_AVAILABILITY\) diff -Nru ceph-16.2.5/qa/standalone/osd/osd-bluefs-volume-ops.sh ceph-16.2.6/qa/standalone/osd/osd-bluefs-volume-ops.sh --- ceph-16.2.5/qa/standalone/osd/osd-bluefs-volume-ops.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/standalone/osd/osd-bluefs-volume-ops.sh 2021-09-16 14:27:19.000000000 +0000 @@ -8,16 +8,6 @@ local dir=$1 shift - export CEPH_MON="127.0.0.1:7146" # git grep '\<7146\>' : there must be only one - export CEPH_ARGS - CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " - CEPH_ARGS+="--mon-host=$CEPH_MON " - CEPH_ARGS+="--bluestore_block_size=2147483648 " - CEPH_ARGS+="--bluestore_block_db_create=true " - CEPH_ARGS+="--bluestore_block_db_size=1073741824 " - CEPH_ARGS+="--bluestore_block_wal_size=536870912 " - CEPH_ARGS+="--bluestore_block_wal_create=true " - CEPH_ARGS+="--bluestore_fsck_on_mount=true " local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do setup $dir || return 1 @@ -33,6 +23,16 @@ if [ $flimit -lt 1536 ]; then echo "Low open file limit ($flimit), test may fail. Increase to 1536 or higher and retry if that happens." fi + export CEPH_MON="127.0.0.1:7146" # git grep '\<7146\>' : there must be only one + export CEPH_ARGS + CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " + CEPH_ARGS+="--mon-host=$CEPH_MON " + CEPH_ARGS+="--bluestore_block_size=2147483648 " + CEPH_ARGS+="--bluestore_block_db_create=true " + CEPH_ARGS+="--bluestore_block_db_size=1073741824 " + CEPH_ARGS+="--bluestore_block_wal_size=536870912 " + CEPH_ARGS+="--bluestore_block_wal_create=true " + CEPH_ARGS+="--bluestore_fsck_on_mount=true " run_mon $dir a || return 1 run_mgr $dir x || return 1 @@ -336,6 +336,63 @@ wait_for_clean || return 1 } + +function TEST_bluestore2() { + local dir=$1 + + local flimit=$(ulimit -n) + if [ $flimit -lt 1536 ]; then + echo "Low open file limit ($flimit), test may fail. Increase to 1536 or higher and retry if that happens." + fi + export CEPH_MON="127.0.0.1:7146" # git grep '\<7146\>' : there must be only one + export CEPH_ARGS + CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none " + CEPH_ARGS+="--mon-host=$CEPH_MON " + CEPH_ARGS+="--bluestore_block_size=4294967296 " + CEPH_ARGS+="--bluestore_block_db_create=true " + CEPH_ARGS+="--bluestore_block_db_size=1073741824 " + CEPH_ARGS+="--bluestore_block_wal_create=false " + CEPH_ARGS+="--bluestore_fsck_on_mount=true " + CEPH_ARGS+="--osd_pool_default_size=1 " + CEPH_ARGS+="--osd_pool_default_min_size=1 " + CEPH_ARGS+="--bluestore_debug_enforce_settings=ssd " + + run_mon $dir a || return 1 + run_mgr $dir x || return 1 + run_osd $dir 0 || return 1 + osd_pid0=$(cat $dir/osd.0.pid) + + sleep 5 + create_pool foo 16 + + # write some objects + timeout 60 rados bench -p foo 10 write --write-omap --no-cleanup #|| return 1 + + #give RocksDB some time to cooldown and put files to slow level(s) + sleep 10 + + spilled_over=$( ceph tell osd.0 perf dump bluefs | jq ".bluefs.slow_used_bytes" ) + test $spilled_over -gt 0 || return 1 + + while kill $osd_pid0; do sleep 1 ; done + ceph osd down 0 + + ceph-bluestore-tool --path $dir/0 \ + --devs-source $dir/0/block.db \ + --dev-target $dir/0/block \ + --command bluefs-bdev-migrate || return 1 + + ceph-bluestore-tool --path $dir/0 \ + --command bluefs-bdev-sizes || return 1 + + ceph-bluestore-tool --path $dir/0 \ + --command fsck || return 1 + + activate_osd $dir 0 || return 1 + osd_pid0=$(cat $dir/osd.0.pid) + + wait_for_clean || return 1 +} main osd-bluefs-volume-ops "$@" diff -Nru ceph-16.2.5/qa/standalone/osd/osd-force-create-pg.sh ceph-16.2.6/qa/standalone/osd/osd-force-create-pg.sh --- ceph-16.2.5/qa/standalone/osd/osd-force-create-pg.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/standalone/osd/osd-force-create-pg.sh 2021-09-16 14:27:19.000000000 +0000 @@ -12,14 +12,15 @@ local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do + setup $dir || return 1 $func $dir || return 1 + teardown $dir || return 1 done } function TEST_reuse_id() { local dir=$1 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=1 --mon_allow_pool_size_one=true || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 diff -Nru ceph-16.2.5/qa/standalone/osd/osd-reuse-id.sh ceph-16.2.6/qa/standalone/osd/osd-reuse-id.sh --- ceph-16.2.5/qa/standalone/osd/osd-reuse-id.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/standalone/osd/osd-reuse-id.sh 2021-09-16 14:27:19.000000000 +0000 @@ -27,14 +27,15 @@ local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do + setup $dir || return 1 $func $dir || return 1 + teardown $dir || return 1 done } function TEST_reuse_id() { local dir=$1 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=1 --mon_allow_pool_size_one=true || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 diff -Nru ceph-16.2.5/qa/standalone/osd/pg-split-merge.sh ceph-16.2.6/qa/standalone/osd/pg-split-merge.sh --- ceph-16.2.5/qa/standalone/osd/pg-split-merge.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/standalone/osd/pg-split-merge.sh 2021-09-16 14:27:19.000000000 +0000 @@ -12,14 +12,15 @@ local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do + setup $dir || return 1 $func $dir || return 1 + teardown $dir || return 1 done } function TEST_a_merge_empty() { local dir=$1 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=3 || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 @@ -87,7 +88,6 @@ function TEST_import_after_merge_and_gap() { local dir=$1 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=1 --mon_allow_pool_size_one=true || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 @@ -162,7 +162,6 @@ function TEST_import_after_split() { local dir=$1 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=1 --mon_allow_pool_size_one=true || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 diff -Nru ceph-16.2.5/qa/standalone/scrub/osd-scrub-repair.sh ceph-16.2.6/qa/standalone/scrub/osd-scrub-repair.sh --- ceph-16.2.5/qa/standalone/scrub/osd-scrub-repair.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/standalone/scrub/osd-scrub-repair.sh 2021-09-16 14:27:19.000000000 +0000 @@ -60,7 +60,9 @@ export -n CEPH_CLI_TEST_DUP_COMMAND local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')} for func in $funcs ; do + setup $dir || return 1 $func $dir || return 1 + teardown $dir || return 1 done } @@ -91,7 +93,6 @@ local dir=$1 local poolname=rbd - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 @@ -103,8 +104,6 @@ corrupt_and_repair_one $dir $poolname $(get_not_primary $poolname SOMETHING) || return 1 # Reproduces http://tracker.ceph.com/issues/8914 corrupt_and_repair_one $dir $poolname $(get_primary $poolname SOMETHING) || return 1 - - teardown $dir || return 1 } # @@ -114,7 +113,6 @@ local dir=$1 local poolname=rbd - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 run_mgr $dir x || return 1 run_osd $dir 0 --osd_scrub_during_recovery=false \ @@ -128,8 +126,6 @@ add_something $dir $poolname || return 1 corrupt_and_repair_one $dir $poolname $(get_not_primary $poolname SOMETHING) || return 1 - - teardown $dir || return 1 } # @@ -139,7 +135,6 @@ local dir=$1 local poolname=rbd - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 run_mgr $dir x || return 1 run_osd $dir 0 --osd_scrub_during_recovery=false \ @@ -153,8 +148,6 @@ add_something $dir $poolname || return 1 scrub_and_not_schedule $dir $poolname $(get_not_primary $poolname SOMETHING) || return 1 - - teardown $dir || return 1 } function scrub_and_not_schedule() { @@ -276,7 +269,6 @@ local poolname=ecpool # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-auto-repair=true \ @@ -285,11 +277,11 @@ --osd-scrub-min-interval=5 \ --osd-scrub-interval-randomize-ratio=0" for id in $(seq 0 2) ; do - if [ "$allow_overwrites" = "true" ]; then + if [ "$allow_overwrites" = "true" ]; then run_osd $dir $id $ceph_osd_args || return 1 - else + else run_osd_filestore $dir $id $ceph_osd_args || return 1 - fi + fi done create_rbd_pool || return 1 wait_for_clean || return 1 @@ -314,9 +306,6 @@ objectstore_tool $dir $(get_not_primary $poolname SOMETHING) SOMETHING list-attrs || return 1 rados --pool $poolname get SOMETHING $dir/COPY || return 1 diff $dir/ORIGINAL $dir/COPY || return 1 - - # Tear down - teardown $dir || return 1 } function TEST_auto_repair_erasure_coded_appends() { @@ -329,16 +318,135 @@ fi } +# initiate a scrub, then check for the (expected) 'scrubbing' and the +# (not expected until an error was identified) 'repair' +# Arguments: osd#, pg, sleep time +function initiate_and_fetch_state() { + local the_osd="osd.$1" + local pgid=$2 + local last_scrub=$(get_last_scrub_stamp $pgid) + + set_config "osd" "$1" "osd_scrub_sleep" "$3" + set_config "osd" "$1" "osd_scrub_auto_repair" "true" + + flush_pg_stats + date --rfc-3339=ns + + # note: must initiate a "regular" (periodic) deep scrub - not an operator-initiated one + env CEPH_ARGS= ceph --format json daemon $(get_asok_path $the_osd) deep_scrub "$pgid" + env CEPH_ARGS= ceph --format json daemon $(get_asok_path $the_osd) scrub "$pgid" + + # wait for 'scrubbing' to appear + for ((i=0; i < 80; i++)); do + + st=`ceph pg $pgid query --format json | jq '.state' ` + echo $i ") state now: " $st + + case "$st" in + *scrubbing*repair* ) echo "found scrub+repair"; return 1;; # PR #41258 should have prevented this + *scrubbing* ) echo "found scrub"; return 0;; + *inconsistent* ) echo "Got here too late. Scrub has already finished"; return 1;; + *recovery* ) echo "Got here too late. Scrub has already finished."; return 1;; + * ) echo $st;; + esac + + if [ $((i % 10)) == 4 ]; then + echo "loop --------> " $i + fi + sleep 0.3 + done + + echo "Timeout waiting for deep-scrub of " $pgid " on " $the_osd " to start" + return 1 +} + +function wait_end_of_scrub() { # osd# pg + local the_osd="osd.$1" + local pgid=$2 + + for ((i=0; i < 40; i++)); do + st=`ceph pg $pgid query --format json | jq '.state' ` + echo "wait-scrub-end state now: " $st + [[ $st =~ (.*scrubbing.*) ]] || break + if [ $((i % 5)) == 4 ] ; then + flush_pg_stats + fi + sleep 0.3 + done + + if [[ $st =~ (.*scrubbing.*) ]] + then + # a timeout + return 1 + fi + return 0 +} + + +function TEST_auto_repair_bluestore_tag() { + local dir=$1 + local poolname=testpool + + # Launch a cluster with 3 seconds scrub interval + setup $dir || return 1 + run_mon $dir a || return 1 + run_mgr $dir x || return 1 + local ceph_osd_args="--osd-scrub-auto-repair=true \ + --osd_deep_scrub_randomize_ratio=0 \ + --osd-scrub-interval-randomize-ratio=0" + for id in $(seq 0 2) ; do + run_osd $dir $id $ceph_osd_args || return 1 + done + + create_pool $poolname 1 1 || return 1 + ceph osd pool set $poolname size 2 + wait_for_clean || return 1 + + # Put an object + local payload=ABCDEF + echo $payload > $dir/ORIGINAL + rados --pool $poolname put SOMETHING $dir/ORIGINAL || return 1 + + # Remove the object from one shard physically + # Restarted osd get $ceph_osd_args passed + objectstore_tool $dir $(get_not_primary $poolname SOMETHING) SOMETHING remove || return 1 + + local pgid=$(get_pg $poolname SOMETHING) + local primary=$(get_primary $poolname SOMETHING) + echo "Affected PG " $pgid " w/ primary " $primary + local last_scrub_stamp="$(get_last_scrub_stamp $pgid)" + initiate_and_fetch_state $primary $pgid "3.0" + r=$? + echo "initiate_and_fetch_state ret: " $r + set_config "osd" "$1" "osd_scrub_sleep" "0" + if [ $r -ne 0 ]; then + return 1 + fi + + wait_end_of_scrub "$primary" "$pgid" || return 1 + ceph pg dump pgs + + # Verify - the file should be back + # Restarted osd get $ceph_osd_args passed + objectstore_tool $dir $(get_not_primary $poolname SOMETHING) SOMETHING list-attrs || return 1 + objectstore_tool $dir $(get_not_primary $poolname SOMETHING) SOMETHING get-bytes $dir/COPY || return 1 + diff $dir/ORIGINAL $dir/COPY || return 1 + grep scrub_finish $dir/osd.${primary}.log + + # Tear down + teardown $dir || return 1 +} + + function TEST_auto_repair_bluestore_basic() { local dir=$1 local poolname=testpool # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-auto-repair=true \ - --osd_deep_scrub_randomize_ratio=0 \ + --osd_deep_scrub_randomize_ratio=0 \ --osd-scrub-interval-randomize-ratio=0" for id in $(seq 0 2) ; do run_osd $dir $id $ceph_osd_args || return 1 @@ -373,9 +481,6 @@ objectstore_tool $dir $(get_not_primary $poolname SOMETHING) SOMETHING get-bytes $dir/COPY || return 1 diff $dir/ORIGINAL $dir/COPY || return 1 grep scrub_finish $dir/osd.${primary}.log - - # Tear down - teardown $dir || return 1 } function TEST_auto_repair_bluestore_scrub() { @@ -383,12 +488,12 @@ local poolname=testpool # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-auto-repair=true \ - --osd_deep_scrub_randomize_ratio=0 \ - --osd-scrub-interval-randomize-ratio=0" + --osd_deep_scrub_randomize_ratio=0 \ + --osd-scrub-interval-randomize-ratio=0 \ + --osd-scrub-backoff-ratio=0" for id in $(seq 0 2) ; do run_osd $dir $id $ceph_osd_args || return 1 done @@ -428,9 +533,6 @@ # This should have caused 1 object to be repaired COUNT=$(ceph pg $pgid query | jq '.info.stats.stat_sum.num_objects_repaired') test "$COUNT" = "1" || return 1 - - # Tear down - teardown $dir || return 1 } function TEST_auto_repair_bluestore_failed() { @@ -438,11 +540,10 @@ local poolname=testpool # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-auto-repair=true \ - --osd_deep_scrub_randomize_ratio=0 \ + --osd_deep_scrub_randomize_ratio=0 \ --osd-scrub-interval-randomize-ratio=0" for id in $(seq 0 2) ; do run_osd $dir $id $ceph_osd_args || return 1 @@ -498,9 +599,6 @@ ceph pg dump pgs ceph pg dump pgs | grep -q -e "^${pgid}.* active+clean " -e "^${pgid}.* active+clean+wait " || return 1 grep scrub_finish $dir/osd.${primary}.log - - # Tear down - teardown $dir || return 1 } function TEST_auto_repair_bluestore_failed_norecov() { @@ -508,11 +606,10 @@ local poolname=testpool # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-auto-repair=true \ - --osd_deep_scrub_randomize_ratio=0 \ + --osd_deep_scrub_randomize_ratio=0 \ --osd-scrub-interval-randomize-ratio=0" for id in $(seq 0 2) ; do run_osd $dir $id $ceph_osd_args || return 1 @@ -552,9 +649,6 @@ grep -q "scrub_finish.*present with no repair possible" $dir/osd.${primary}.log || return 1 ceph pg dump pgs ceph pg dump pgs | grep -q "^${pgid}.*+failed_repair" || return 1 - - # Tear down - teardown $dir || return 1 } function TEST_repair_stats() { @@ -566,7 +660,6 @@ local REPAIRS=20 # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd_deep_scrub_randomize_ratio=0 \ @@ -626,9 +719,6 @@ ceph pg dump --format=json-pretty | jq ".pg_map.osd_stats_sum" COUNT=$(ceph pg dump --format=json-pretty | jq ".pg_map.osd_stats_sum.num_shards_repaired") test "$COUNT" = "$REPAIRS" || return 1 - - # Tear down - teardown $dir || return 1 } function TEST_repair_stats_ec() { @@ -641,7 +731,6 @@ local allow_overwrites=false # Launch a cluster with 5 seconds scrub interval - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd_deep_scrub_randomize_ratio=0 \ @@ -704,9 +793,6 @@ ceph pg dump --format=json-pretty | jq ".pg_map.osd_stats_sum" COUNT=$(ceph pg dump --format=json-pretty | jq ".pg_map.osd_stats_sum.num_shards_repaired") test "$COUNT" = "$REPAIRS" || return 1 - - # Tear down - teardown $dir || return 1 } function corrupt_and_repair_jerasure() { @@ -714,7 +800,6 @@ local allow_overwrites=$2 local poolname=ecpool - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 for id in $(seq 0 3) ; do @@ -729,8 +814,6 @@ create_ec_pool $poolname $allow_overwrites k=2 m=2 || return 1 corrupt_and_repair_erasure_coded $dir $poolname || return 1 - - teardown $dir || return 1 } function TEST_corrupt_and_repair_jerasure_appends() { @@ -748,7 +831,6 @@ local allow_overwrites=$2 local poolname=ecpool - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 for id in $(seq 0 9) ; do @@ -763,8 +845,6 @@ create_ec_pool $poolname $allow_overwrites k=4 m=2 l=3 plugin=lrc || return 1 corrupt_and_repair_erasure_coded $dir $poolname || return 1 - - teardown $dir || return 1 } function TEST_corrupt_and_repair_lrc_appends() { @@ -783,7 +863,6 @@ local poolname=ecpool local payload=ABCDEF - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 for id in $(seq 0 3) ; do @@ -831,8 +910,6 @@ ceph -s|grep "4 up" || return 1 ceph -s|grep "4 in" || return 1 ceph -s|grep "1/1 objects unfound" || return 1 - - teardown $dir || return 1 } function TEST_unfound_erasure_coded_appends() { @@ -853,7 +930,6 @@ local allow_overwrites=$2 local poolname=ecpool - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 for id in $(seq 0 2) ; do @@ -913,8 +989,6 @@ matches=$(ceph pg $pg list_unfound | egrep "MOBJ0|MOBJ1" | wc -l) [ $matches -eq 2 ] && break done - - teardown $dir || return 1 } function TEST_list_missing_erasure_coded_appends() { @@ -935,7 +1009,6 @@ local poolname=csr_pool local total_objs=19 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 @@ -3530,7 +3603,6 @@ fi ceph osd pool rm $poolname $poolname --yes-i-really-really-mean-it - teardown $dir || return 1 } @@ -3543,7 +3615,6 @@ local poolname=ecpool local total_objs=7 - setup $dir || return 1 run_mon $dir a || return 1 run_mgr $dir x || return 1 for id in $(seq 0 2) ; do @@ -5690,7 +5761,6 @@ fi ceph osd pool rm $poolname $poolname --yes-i-really-really-mean-it - teardown $dir || return 1 } function TEST_corrupt_scrub_erasure_appends() { @@ -5711,7 +5781,6 @@ local poolname=psr_pool local objname=POBJ - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-interval-randomize-ratio=0 --osd-deep-scrub-randomize-ratio=0 " @@ -5803,7 +5872,6 @@ local conf_overdue_seconds=$(calc $i7_days + $i1_day + \( $i7_days \* $overdue \) ) local pool_overdue_seconds=$(calc $i14_days + $i1_day + \( $i14_days \* $overdue \) ) - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=1 --mon_allow_pool_size_one=true || return 1 run_mgr $dir x --mon_warn_pg_not_scrubbed_ratio=${overdue} --mon_warn_pg_not_deep_scrubbed_ratio=${overdue} || return 1 run_osd $dir 0 $ceph_osd_args --osd_scrub_backoff_ratio=0 || return 1 @@ -5870,7 +5938,6 @@ ceph health detail | grep "not deep-scrubbed since" return 1 fi - return 0 } # @@ -5881,7 +5948,6 @@ local poolname=csr_pool local total_objs=2 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=2 || return 1 run_mgr $dir x || return 1 run_osd $dir 0 || return 1 @@ -6141,7 +6207,6 @@ fi ceph osd pool rm $poolname $poolname --yes-i-really-really-mean-it - teardown $dir || return 1 } function TEST_request_scrub_priority() { @@ -6151,7 +6216,6 @@ local OBJECTS=64 local PGS=8 - setup $dir || return 1 run_mon $dir a --osd_pool_default_size=1 --mon_allow_pool_size_one=true || return 1 run_mgr $dir x || return 1 local ceph_osd_args="--osd-scrub-interval-randomize-ratio=0 --osd-deep-scrub-randomize-ratio=0 " @@ -6199,8 +6263,6 @@ # Verify that the requested scrub ran first grep "log_channel.*scrub ok" $dir/osd.${primary}.log | grep -v purged_snaps | head -1 | sed 's/.*[[]DBG[]]//' | grep -q $pg || return 1 - - return 0 } diff -Nru ceph-16.2.5/qa/suites/fs/functional/tasks/mds-full.yaml ceph-16.2.6/qa/suites/fs/functional/tasks/mds-full.yaml --- ceph-16.2.5/qa/suites/fs/functional/tasks/mds-full.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/functional/tasks/mds-full.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -12,6 +12,8 @@ - is full \(reached quota - POOL_FULL - POOL_BACKFILLFULL + - PG_RECOVERY_FULL + - PG_DEGRADED conf: mon: mon osd nearfull ratio: 0.6 diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/bluestore-bitmap.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/bluestore-bitmap.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/bluestore-bitmap.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/bluestore-bitmap.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,43 @@ +overrides: + thrashosds: + bdev_inject_crash: 2 + bdev_inject_crash_probability: .5 + ceph: + fs: xfs + conf: + osd: + osd objectstore: bluestore + bluestore block size: 96636764160 + debug bluestore: 1/20 + debug bluefs: 1/20 + debug rocksdb: 4/10 + bluestore fsck on mount: true + bluestore allocator: bitmap + # lower the full ratios since we can fill up a 100gb osd so quickly + mon osd full ratio: .9 + mon osd backfillfull_ratio: .85 + mon osd nearfull ratio: .8 + osd failsafe full ratio: .95 +# this doesn't work with failures bc the log writes are not atomic across the two backends +# bluestore bluefs env mirror: true + bdev enable discard: true + bdev async discard: true + ceph-deploy: + fs: xfs + bluestore: yes + conf: + osd: + osd objectstore: bluestore + bluestore block size: 96636764160 + debug bluestore: 1/20 + debug bluefs: 1/20 + debug rocksdb: 4/10 + bluestore fsck on mount: true + # lower the full ratios since we can fill up a 100gb osd so quickly + mon osd full ratio: .9 + mon osd backfillfull_ratio: .85 + mon osd nearfull ratio: .8 + osd failsafe full ratio: .95 + bdev enable discard: true + bdev async discard: true + diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/centos_latest.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/centos_latest.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/centos_latest.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/centos_latest.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,6 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/client.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/client.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/client.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/client.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,9 @@ +overrides: + ceph: + conf: + client: + client mount timeout: 600 + debug ms: 1 + debug client: 20 + rados mon op timeout: 15m + rados osd op timeout: 15m diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/mds.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/mds.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/mds.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/mds.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,13 @@ +overrides: + ceph: + conf: + mds: + debug mds: 20 + debug ms: 1 + mds debug frag: true + mds debug scatterstat: true + mds op complaint time: 180 + mds verify scatter: true + osd op complaint time: 180 + rados mon op timeout: 15m + rados osd op timeout: 15m diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/mon.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/mon.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/mon.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/mon.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +overrides: + ceph: + conf: + mon: + mon op complaint time: 120 diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/osd.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/osd.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/conf/osd.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/conf/osd.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +overrides: + ceph: + conf: + osd: + osd op complaint time: 180 diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/no-mds-cluster.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/no-mds-cluster.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/no-mds-cluster.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/no-mds-cluster.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,6 @@ +roles: +- [mon.a, mon.b, mon.c, mgr.x, mgr.y, osd.0, osd.1, osd.2, osd.3] +openstack: +- volumes: # attached to each instance + count: 4 + size: 10 # GB diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/overrides/pg-warn.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/overrides/pg-warn.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/overrides/pg-warn.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/overrides/pg-warn.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +overrides: + ceph: + conf: + global: + mon pg warn min per osd: 0 diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/overrides/whitelist_health.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/overrides/whitelist_health.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/overrides/whitelist_health.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/overrides/whitelist_health.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,12 @@ +overrides: + ceph: + log-ignorelist: + - overall HEALTH_ + - \(FS_DEGRADED\) + - \(MDS_FAILED\) + - \(MDS_DEGRADED\) + - \(FS_WITH_FAILED_MDS\) + - \(MDS_DAMAGE\) + - \(MDS_ALL_DOWN\) + - \(MDS_UP_LESS_THAN_MAX\) + - \(FS_INLINE_DATA_DEPRECATED\) diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/overrides/whitelist_wrongly_marked_down.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/overrides/whitelist_wrongly_marked_down.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/overrides/whitelist_wrongly_marked_down.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/overrides/whitelist_wrongly_marked_down.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,9 @@ +overrides: + ceph: + log-ignorelist: + - overall HEALTH_ + - \(OSD_DOWN\) + - \(OSD_ + - but it is still running +# MDS daemon 'b' is not responding, replacing it as rank 0 with standby 'a' + - is not responding diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/README ceph-16.2.6/qa/suites/fs/upgrade/nofs/README --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/README 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/README 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,3 @@ +This test just verifies that upgrades work with no file system present. In +particular, catch that MDSMonitor doesn't blow up somehow with version +mismatches. diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/tasks/0-octopus.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/tasks/0-octopus.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/tasks/0-octopus.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/tasks/0-octopus.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,38 @@ +meta: +- desc: | + install ceph/octopus latest +tasks: +- install: + branch: octopus + exclude_packages: + - librados3 + - ceph-mgr-dashboard + - ceph-mgr-diskprediction-local + - ceph-mgr-rook + - ceph-mgr-cephadm + - cephadm + extra_packages: ['librados2'] +- print: "**** done installing octopus" +- ceph: + log-ignorelist: + - overall HEALTH_ + - \(FS_ + - \(MDS_ + - \(OSD_ + - \(MON_DOWN\) + - \(CACHE_POOL_ + - \(POOL_ + - \(MGR_DOWN\) + - \(PG_ + - \(SMALLER_PGP_NUM\) + - Monitor daemon marked osd + - Behind on trimming + - Manager daemon + conf: + global: + mon warn on pool no app: false + ms bind msgr2: false +- exec: + osd.0: + - ceph osd set-require-min-compat-client octopus +- print: "**** done ceph" diff -Nru ceph-16.2.5/qa/suites/fs/upgrade/nofs/tasks/1-upgrade.yaml ceph-16.2.6/qa/suites/fs/upgrade/nofs/tasks/1-upgrade.yaml --- ceph-16.2.5/qa/suites/fs/upgrade/nofs/tasks/1-upgrade.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/fs/upgrade/nofs/tasks/1-upgrade.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,45 @@ +overrides: + ceph: + log-ignorelist: + - scrub mismatch + - ScrubResult + - wrongly marked + - \(POOL_APP_NOT_ENABLED\) + - \(SLOW_OPS\) + - overall HEALTH_ + - \(MON_MSGR2_NOT_ENABLED\) + - slow request + conf: + global: + bluestore warn on legacy statfs: false + bluestore warn on no per pool omap: false + mon: + mon warn on osd down out interval zero: false + +tasks: +- print: "*** upgrading, no cephfs present" +- exec: + mon.a: + - ceph fs dump +- install.upgrade: + mon.a: +- print: "**** done install.upgrade" +- ceph.restart: + daemons: [mon.*, mgr.*] + mon-health-to-clog: false + wait-for-healthy: false +- ceph.healthy: +- ceph.restart: + daemons: [osd.*] + wait-for-healthy: false + wait-for-osds-up: true +- exec: + mon.a: + - ceph versions + - ceph osd dump -f json-pretty + - ceph fs dump + - ceph osd require-osd-release octopus + - for f in `ceph osd pool ls` ; do ceph osd pool set $f pg_autoscale_mode off ; done + #- ceph osd set-require-min-compat-client octopus +- ceph.healthy: +- print: "**** done ceph.restart" diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/orch/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/dashboard/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/orchestrator_cli/0-random-distro$/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke/distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke/distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke/distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke-roleless/0-distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke-roleless/0-distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/smoke-singlehost/0-distro$/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/thrash/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/with-work/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/with-work/0-distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/with-work/0-distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/cephadm/workunits/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/dashboard/centos_8.2_container_tools_3.0.yaml ceph-16.2.6/qa/suites/rados/dashboard/centos_8.2_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/rados/dashboard/centos_8.2_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/dashboard/centos_8.2_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/rados/dashboard/tasks/dashboard.yaml ceph-16.2.6/qa/suites/rados/dashboard/tasks/dashboard.yaml --- ceph-16.2.5/qa/suites/rados/dashboard/tasks/dashboard.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rados/dashboard/tasks/dashboard.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -57,3 +57,4 @@ - tasks.mgr.dashboard.test_summary - tasks.mgr.dashboard.test_telemetry - tasks.mgr.dashboard.test_user + - tasks.mgr.dashboard.test_motd diff -Nru ceph-16.2.5/qa/suites/rgw/ignore-pg-availability.yaml ceph-16.2.6/qa/suites/rgw/ignore-pg-availability.yaml --- ceph-16.2.5/qa/suites/rgw/ignore-pg-availability.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rgw/ignore-pg-availability.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -# https://tracker.ceph.com/issues/45802 -overrides: - ceph: - log-ignorelist: - - \(PG_AVAILABILITY\) diff -Nru ceph-16.2.5/qa/suites/rgw/multisite/overrides.yaml ceph-16.2.6/qa/suites/rgw/multisite/overrides.yaml --- ceph-16.2.5/qa/suites/rgw/multisite/overrides.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/rgw/multisite/overrides.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -14,5 +14,6 @@ rgw md log max shards: 4 rgw data log num shards: 4 rgw sync obj etag verify: true + rgw sync meta inject err probability: 0.1 rgw: compression type: random diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/bluestore-bitmap.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/bluestore-bitmap.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/bluestore-bitmap.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/bluestore-bitmap.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,43 @@ +overrides: + thrashosds: + bdev_inject_crash: 2 + bdev_inject_crash_probability: .5 + ceph: + fs: xfs + conf: + osd: + osd objectstore: bluestore + bluestore block size: 96636764160 + debug bluestore: 1/20 + debug bluefs: 1/20 + debug rocksdb: 4/10 + bluestore fsck on mount: true + bluestore allocator: bitmap + # lower the full ratios since we can fill up a 100gb osd so quickly + mon osd full ratio: .9 + mon osd backfillfull_ratio: .85 + mon osd nearfull ratio: .8 + osd failsafe full ratio: .95 +# this doesn't work with failures bc the log writes are not atomic across the two backends +# bluestore bluefs env mirror: true + bdev enable discard: true + bdev async discard: true + ceph-deploy: + fs: xfs + bluestore: yes + conf: + osd: + osd objectstore: bluestore + bluestore block size: 96636764160 + debug bluestore: 1/20 + debug bluefs: 1/20 + debug rocksdb: 4/10 + bluestore fsck on mount: true + # lower the full ratios since we can fill up a 100gb osd so quickly + mon osd full ratio: .9 + mon osd backfillfull_ratio: .85 + mon osd nearfull ratio: .8 + osd failsafe full ratio: .95 + bdev enable discard: true + bdev async discard: true + diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/centos_latest.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/centos_latest.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/centos_latest.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/centos_latest.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,6 @@ +os_type: centos +os_version: "8.2" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/client.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/client.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/client.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/client.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,9 @@ +overrides: + ceph: + conf: + client: + client mount timeout: 600 + debug ms: 1 + debug client: 20 + rados mon op timeout: 15m + rados osd op timeout: 15m diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/mds.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/mds.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/mds.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/mds.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,13 @@ +overrides: + ceph: + conf: + mds: + debug mds: 20 + debug ms: 1 + mds debug frag: true + mds debug scatterstat: true + mds op complaint time: 180 + mds verify scatter: true + osd op complaint time: 180 + rados mon op timeout: 15m + rados osd op timeout: 15m diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/mon.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/mon.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/mon.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/mon.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +overrides: + ceph: + conf: + mon: + mon op complaint time: 120 diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/osd.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/osd.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/conf/osd.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/conf/osd.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +overrides: + ceph: + conf: + osd: + osd op complaint time: 180 diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/no-mds-cluster.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/no-mds-cluster.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/no-mds-cluster.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/no-mds-cluster.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,6 @@ +roles: +- [mon.a, mon.b, mon.c, mgr.x, mgr.y, osd.0, osd.1, osd.2, osd.3] +openstack: +- volumes: # attached to each instance + count: 4 + size: 10 # GB diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/overrides/pg-warn.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/overrides/pg-warn.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/overrides/pg-warn.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/overrides/pg-warn.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,5 @@ +overrides: + ceph: + conf: + global: + mon pg warn min per osd: 0 diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_health.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_health.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_health.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_health.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,12 @@ +overrides: + ceph: + log-ignorelist: + - overall HEALTH_ + - \(FS_DEGRADED\) + - \(MDS_FAILED\) + - \(MDS_DEGRADED\) + - \(FS_WITH_FAILED_MDS\) + - \(MDS_DAMAGE\) + - \(MDS_ALL_DOWN\) + - \(MDS_UP_LESS_THAN_MAX\) + - \(FS_INLINE_DATA_DEPRECATED\) diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_wrongly_marked_down.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_wrongly_marked_down.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_wrongly_marked_down.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/overrides/whitelist_wrongly_marked_down.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,9 @@ +overrides: + ceph: + log-ignorelist: + - overall HEALTH_ + - \(OSD_DOWN\) + - \(OSD_ + - but it is still running +# MDS daemon 'b' is not responding, replacing it as rank 0 with standby 'a' + - is not responding diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/README ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/README --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/README 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/README 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,3 @@ +This test just verifies that upgrades work with no file system present. In +particular, catch that MDSMonitor doesn't blow up somehow with version +mismatches. diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/tasks/0-octopus.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/tasks/0-octopus.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/tasks/0-octopus.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/tasks/0-octopus.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,38 @@ +meta: +- desc: | + install ceph/octopus latest +tasks: +- install: + branch: octopus + exclude_packages: + - librados3 + - ceph-mgr-dashboard + - ceph-mgr-diskprediction-local + - ceph-mgr-rook + - ceph-mgr-cephadm + - cephadm + extra_packages: ['librados2'] +- print: "**** done installing octopus" +- ceph: + log-ignorelist: + - overall HEALTH_ + - \(FS_ + - \(MDS_ + - \(OSD_ + - \(MON_DOWN\) + - \(CACHE_POOL_ + - \(POOL_ + - \(MGR_DOWN\) + - \(PG_ + - \(SMALLER_PGP_NUM\) + - Monitor daemon marked osd + - Behind on trimming + - Manager daemon + conf: + global: + mon warn on pool no app: false + ms bind msgr2: false +- exec: + osd.0: + - ceph osd set-require-min-compat-client octopus +- print: "**** done ceph" diff -Nru ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/tasks/1-upgrade.yaml ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/tasks/1-upgrade.yaml --- ceph-16.2.5/qa/suites/upgrade/cephfs/nofs/tasks/1-upgrade.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/cephfs/nofs/tasks/1-upgrade.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,45 @@ +overrides: + ceph: + log-ignorelist: + - scrub mismatch + - ScrubResult + - wrongly marked + - \(POOL_APP_NOT_ENABLED\) + - \(SLOW_OPS\) + - overall HEALTH_ + - \(MON_MSGR2_NOT_ENABLED\) + - slow request + conf: + global: + bluestore warn on legacy statfs: false + bluestore warn on no per pool omap: false + mon: + mon warn on osd down out interval zero: false + +tasks: +- print: "*** upgrading, no cephfs present" +- exec: + mon.a: + - ceph fs dump +- install.upgrade: + mon.a: +- print: "**** done install.upgrade" +- ceph.restart: + daemons: [mon.*, mgr.*] + mon-health-to-clog: false + wait-for-healthy: false +- ceph.healthy: +- ceph.restart: + daemons: [osd.*] + wait-for-healthy: false + wait-for-osds-up: true +- exec: + mon.a: + - ceph versions + - ceph osd dump -f json-pretty + - ceph fs dump + - ceph osd require-osd-release octopus + - for f in `ceph osd pool ls` ; do ceph osd pool set $f pg_autoscale_mode off ; done + #- ceph osd set-require-min-compat-client octopus +- ceph.healthy: +- print: "**** done ceph.restart" diff -Nru ceph-16.2.5/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/octopus-x/parallel/0-distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/upgrade/octopus-x/parallel/0-distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/upgrade/octopus-x/parallel/0-distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/upgrade/octopus-x/parallel/0-distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/octopus-x/parallel/0-distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.2_kubic_stable.yaml ceph-16.2.6/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.2_kubic_stable.yaml --- ceph-16.2.5/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.2_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.2_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: centos -os_version: "8.2" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.3_container_tools_3.0.yaml ceph-16.2.6/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.3_container_tools_3.0.yaml --- ceph-16.2.5/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.3_container_tools_3.0.yaml 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/octopus-x/stress-split/0-distro/centos_8.3_container_tools_3.0.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,14 @@ +os_type: centos +os_version: "8.3" +overrides: + selinux: + whitelist: + - scontext=system_u:system_r:logrotate_t:s0 + +tasks: +- pexec: + all: + - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup + - sudo dnf -y module reset container-tools + - sudo dnf -y module install container-tools:3.0 + - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/upgrade/octopus-x/stress-split/0-distro/rhel_8.3_kubic_stable.yaml ceph-16.2.6/qa/suites/upgrade/octopus-x/stress-split/0-distro/rhel_8.3_kubic_stable.yaml --- ceph-16.2.5/qa/suites/upgrade/octopus-x/stress-split/0-distro/rhel_8.3_kubic_stable.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/octopus-x/stress-split/0-distro/rhel_8.3_kubic_stable.yaml 1970-01-01 00:00:00.000000000 +0000 @@ -1,18 +0,0 @@ -os_type: rhel -os_version: "8.3" -overrides: - selinux: - whitelist: - - scontext=system_u:system_r:logrotate_t:s0 - -tasks: -- pexec: - all: - - sudo cp /etc/containers/registries.conf /etc/containers/registries.conf.backup - - sudo dnf -y module disable container-tools - - sudo dnf -y install 'dnf-command(copr)' - - sudo dnf -y copr enable rhcontainerbot/container-selinux - - sudo curl -L -o /etc/yum.repos.d/devel:kubic:libcontainers:stable.repo https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/CentOS_8/devel:kubic:libcontainers:stable.repo - - sudo dnf remove -y podman - - sudo dnf -y install podman - - sudo cp /etc/containers/registries.conf.backup /etc/containers/registries.conf diff -Nru ceph-16.2.5/qa/suites/upgrade/pacific-p2p/pacific-p2p-parallel/point-to-point-upgrade.yaml ceph-16.2.6/qa/suites/upgrade/pacific-p2p/pacific-p2p-parallel/point-to-point-upgrade.yaml --- ceph-16.2.5/qa/suites/upgrade/pacific-p2p/pacific-p2p-parallel/point-to-point-upgrade.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/pacific-p2p/pacific-p2p-parallel/point-to-point-upgrade.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -3,7 +3,7 @@ Run ceph on two nodes, using one of them as a client, with a separate client-only node. Use xfs beneath the osds. - install ceph/pacific v16.2.2 and the v16.2.x point versions + install ceph/pacific v16.2.4 and the v16.2.x point versions run workload and upgrade-sequence in parallel (every point release should be tested) run workload and upgrade-sequence in parallel @@ -69,32 +69,32 @@ count: 3 size: 30 # GB tasks: -- print: "**** done pacific v16.2.0 about to install" +- print: "**** done pacific about to install v16.2.4 " - install: - tag: v16.2.2 + tag: v16.2.4 # line below can be removed its from jewel test #exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev', 'librgw2'] -- print: "**** done v16.2.2 install" +- print: "**** done v16.2.4 install" - ceph: fs: xfs add_osds_to_crush: true - print: "**** done ceph xfs" - sequential: - workload -- print: "**** done workload v16.2.2" +- print: "**** done workload v16.2.4" -####### upgrade to v16.2.3 +####### upgrade to v16.2.5 - install.upgrade: #exclude_packages: ['ceph-mgr','libcephfs2','libcephfs-devel','libcephfs-dev'] mon.a: - tag: v16.2.3 + tag: v16.2.5 mon.b: - tag: v16.2.3 + tag: v16.2.5 - parallel: - workload_pacific - upgrade-sequence_pacific -- print: "**** done parallel pacific v16.2.3" +- print: "**** done parallel pacific v16.2.5" #### upgrade to latest pacific - install.upgrade: diff -Nru ceph-16.2.5/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/1-ceph-install/pacific..yaml ceph-16.2.6/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/1-ceph-install/pacific..yaml --- ceph-16.2.5/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/1-ceph-install/pacific..yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/1-ceph-install/pacific..yaml 2021-09-16 14:27:19.000000000 +0000 @@ -1,13 +1,13 @@ meta: - desc: | - install ceph/pacific v16.2.3 + install ceph/pacific v16.2.4 Overall upgrade path is - pacific-latest.point => pacific-latest tasks: - install: - tag: v16.2.3 + tag: v16.2.4 exclude_packages: ['librados3'] extra_packages: ['librados2'] -- print: "**** done install pacific v16.2.3" +- print: "**** done install pacific v16.2.4" - ceph: - exec: osd.0: diff -Nru ceph-16.2.5/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/6-final-workload/rbd-python.yaml ceph-16.2.6/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/6-final-workload/rbd-python.yaml --- ceph-16.2.5/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/6-final-workload/rbd-python.yaml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/suites/upgrade/pacific-p2p/pacific-p2p-stress-split/6-final-workload/rbd-python.yaml 2021-09-16 14:27:19.000000000 +0000 @@ -3,7 +3,7 @@ librbd python api tests tasks: - workunit: - tag: v16.2.0 + tag: v16.2.4 clients: client.0: - rbd/test_librbd_python.sh diff -Nru ceph-16.2.5/qa/tasks/cephfs/caps_helper.py ceph-16.2.6/qa/tasks/cephfs/caps_helper.py --- ceph-16.2.5/qa/tasks/cephfs/caps_helper.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/caps_helper.py 2021-09-16 14:27:19.000000000 +0000 @@ -60,7 +60,7 @@ self.assertEqual(data, contents1) def conduct_neg_test_for_write_caps(self, filepaths, mounts): - cmdargs = ['echo', 'some random data', Raw('|'), 'sudo', 'tee'] + cmdargs = ['echo', 'some random data', Raw('|'), 'tee'] for mount in mounts: for path in filepaths: diff -Nru ceph-16.2.5/qa/tasks/cephfs/cephfs_test_case.py ceph-16.2.6/qa/tasks/cephfs/cephfs_test_case.py --- ceph-16.2.5/qa/tasks/cephfs/cephfs_test_case.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/cephfs_test_case.py 2021-09-16 14:27:19.000000000 +0000 @@ -4,12 +4,10 @@ import re from shlex import split as shlex_split -from io import StringIO from tasks.ceph_test_case import CephTestCase from teuthology import contextutil -from teuthology.misc import sudo_write_file from teuthology.orchestra import run from teuthology.orchestra.run import CommandFailedError @@ -445,9 +443,7 @@ return self.run_cluster_cmd(f'auth get {self.client_name}') def create_keyring_file(self, remote, keyring): - keyring_path = remote.run(args=['mktemp'], stdout=StringIO()).\ - stdout.getvalue().strip() - sudo_write_file(remote, keyring_path, keyring) + keyring_path = remote.mktemp(data=keyring) # required when triggered using vstart_runner.py. remote.run(args=['chmod', '644', keyring_path]) diff -Nru ceph-16.2.5/qa/tasks/cephfs/filesystem.py ceph-16.2.6/qa/tasks/cephfs/filesystem.py --- ceph-16.2.5/qa/tasks/cephfs/filesystem.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/filesystem.py 2021-09-16 14:27:19.000000000 +0000 @@ -71,9 +71,12 @@ """ Operations on a snapshot of the FSMap. """ - def __init__(self, mon_manager): + def __init__(self, mon_manager, epoch=None): self.mon = mon_manager - self.map = json.loads(self.mon.raw_cluster_cmd("fs", "dump", "--format=json")) + cmd = ["fs", "dump", "--format=json"] + if epoch is not None: + cmd.append(str(epoch)) + self.map = json.loads(self.mon.raw_cluster_cmd(*cmd)) def __str__(self): return json.dumps(self.map, indent = 2, sort_keys = True) @@ -368,8 +371,8 @@ def newfs(self, name='cephfs', create=True): return Filesystem(self._ctx, name=name, create=create) - def status(self): - return FSStatus(self.mon_manager) + def status(self, epoch=None): + return FSStatus(self.mon_manager, epoch) def get_standby_daemons(self): return set([s['name'] for s in self.status().get_standbys()]) @@ -611,13 +614,34 @@ def set_allow_new_snaps(self, yes): self.set_var("allow_new_snaps", yes, '--yes-i-really-mean-it') + def compat(self, *args): + a = map(lambda x: str(x).lower(), args) + self.mon_manager.raw_cluster_cmd("fs", "compat", self.name, *a) + + def add_compat(self, *args): + self.compat("add_compat", *args) + + def add_incompat(self, *args): + self.compat("add_incompat", *args) + + def rm_compat(self, *args): + self.compat("rm_compat", *args) + + def rm_incompat(self, *args): + self.compat("rm_incompat", *args) + def required_client_features(self, *args, **kwargs): c = ["fs", "required_client_features", self.name, *args] return self.mon_manager.run_cluster_cmd(args=c, **kwargs) - # In Octopus+, the PG count can be omitted to use the default. We keep the - # hard-coded value for deployments of Mimic/Nautilus. - pgs_per_fs_pool = 8 + # Since v15.1.0 the pg autoscale mode has been enabled as default, + # will let the pg autoscale mode to calculate the pg_num as needed. + # We set the pg_num_min to 64 to make sure that pg autoscale mode + # won't set the pg_num to low to fix Tracker#45434. + pg_num = 64 + pg_num_min = 64 + target_size_ratio = 0.9 + target_size_ratio_ec = 0.9 def create(self): if self.name is None: @@ -629,13 +653,22 @@ else: data_pool_name = self.data_pool_name + # will use the ec pool to store the data and a small amount of + # metadata still goes to the primary data pool for all files. + if not self.metadata_overlay and self.ec_profile and 'disabled' not in self.ec_profile: + self.target_size_ratio = 0.05 + log.debug("Creating filesystem '{0}'".format(self.name)) self.mon_manager.raw_cluster_cmd('osd', 'pool', 'create', - self.metadata_pool_name, self.pgs_per_fs_pool.__str__()) + self.metadata_pool_name, str(self.pg_num), + '--pg_num_min', str(self.pg_num_min)) self.mon_manager.raw_cluster_cmd('osd', 'pool', 'create', - data_pool_name, self.pgs_per_fs_pool.__str__()) + data_pool_name, str(self.pg_num), + '--pg_num_min', str(self.pg_num_min), + '--target_size_ratio', + str(self.target_size_ratio)) if self.metadata_overlay: self.mon_manager.raw_cluster_cmd('fs', 'new', @@ -654,9 +687,10 @@ cmd.extend(self.ec_profile) self.mon_manager.raw_cluster_cmd(*cmd) self.mon_manager.raw_cluster_cmd( - 'osd', 'pool', 'create', - ec_data_pool_name, self.pgs_per_fs_pool.__str__(), 'erasure', - ec_data_pool_name) + 'osd', 'pool', 'create', ec_data_pool_name, + 'erasure', ec_data_pool_name, + '--pg_num_min', str(self.pg_num_min), + '--target_size_ratio', str(self.target_size_ratio_ec)) self.mon_manager.raw_cluster_cmd( 'osd', 'pool', 'set', ec_data_pool_name, 'allow_ec_overwrites', 'true') @@ -693,12 +727,15 @@ self.getinfo(refresh = True) + # wait pgs to be clean + self.mon_manager.wait_for_clean() + def run_client_payload(self, cmd): # avoid circular dep by importing here: from tasks.cephfs.fuse_mount import FuseMount d = misc.get_testdir(self._ctx) m = FuseMount(self._ctx, {}, d, "admin", self.client_remote, cephfs_name=self.name) - m.mount() + m.mount_wait() m.run_shell_payload(cmd) m.umount_wait(require_clean=True) @@ -810,7 +847,8 @@ def add_data_pool(self, name, create=True): if create: - self.mon_manager.raw_cluster_cmd('osd', 'pool', 'create', name, self.pgs_per_fs_pool.__str__()) + self.mon_manager.raw_cluster_cmd('osd', 'pool', 'create', name, + '--pg_num_min', str(self.pg_num_min)) self.mon_manager.raw_cluster_cmd('fs', 'add_data_pool', self.name, name) self.get_pool_names(refresh = True) for poolid, fs_name in self.data_pools.items(): @@ -863,6 +901,12 @@ raise RuntimeError("can't set filesystem name if its fscid is set") self.data_pool_name = name + def get_pool_pg_num(self, pool_name): + pgs = json.loads(self.mon_manager.raw_cluster_cmd('osd', 'pool', 'get', + pool_name, 'pg_num', + '--format=json-pretty')) + return int(pgs['pg_num']) + def get_namespace_id(self): return self.id diff -Nru ceph-16.2.5/qa/tasks/cephfs/fuse_mount.py ceph-16.2.6/qa/tasks/cephfs/fuse_mount.py --- ceph-16.2.5/qa/tasks/cephfs/fuse_mount.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/fuse_mount.py 2021-09-16 14:27:19.000000000 +0000 @@ -446,7 +446,7 @@ client_name="client.{0}".format(self.client_id), mountpoint=self.mountpoint) - asok_path = self.run_python(pyscript) + asok_path = self.run_python(pyscript, sudo=True) log.info("Found client admin socket at {0}".format(asok_path)) return asok_path diff -Nru ceph-16.2.5/qa/tasks/cephfs/kernel_mount.py ceph-16.2.6/qa/tasks/cephfs/kernel_mount.py --- ceph-16.2.5/qa/tasks/cephfs/kernel_mount.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/kernel_mount.py 2021-09-16 14:27:19.000000000 +0000 @@ -1,5 +1,6 @@ import json import logging +import os import re from io import StringIO @@ -165,64 +166,76 @@ if self.mounted: self.umount() - def _find_debug_dir(self): + def _get_debug_dir(self): """ - Find the debugfs folder for this mount + Get the debugfs folder for this mount """ - pyscript = dedent(""" - import glob - import os - import json - def get_id_to_dir(): - result = {} - for dir in glob.glob("/sys/kernel/debug/ceph/*"): - mds_sessions_lines = open(os.path.join(dir, "mds_sessions")).readlines() - client_id = mds_sessions_lines[1].split()[1].strip('"') + cluster_name = 'ceph' + fsid = self.ctx.ceph[cluster_name].fsid - result[client_id] = dir - return result + global_id = self._get_global_id() - print(json.dumps(get_id_to_dir())) - """) - - output = self.client_remote.sh([ - 'sudo', 'python3', '-c', pyscript - ], timeout=(5*60)) - client_id_to_dir = json.loads(output) - - try: - return client_id_to_dir[self.client_id] - except KeyError: - log.error("Client id '{0}' debug dir not found (clients seen were: {1})".format( - self.client_id, ",".join(client_id_to_dir.keys()) - )) - raise + return os.path.join("/sys/kernel/debug/ceph/", f"{fsid}.client{global_id}") def read_debug_file(self, filename): """ Read the debug file "filename", return None if the file doesn't exist. """ - debug_dir = self._find_debug_dir() - pyscript = dedent(""" - import os - - print(open(os.path.join("{debug_dir}", "{filename}")).read()) - """).format(debug_dir=debug_dir, filename=filename) + path = os.path.join(self._get_debug_dir(), filename) + stdout = StringIO() stderr = StringIO() try: - output = self.client_remote.sh([ - 'sudo', 'python3', '-c', pyscript - ], stderr=stderr, timeout=(5*60)) - - return output + self.run_shell_payload(f"sudo dd if={path}", timeout=(5*60), + stdout=stdout, stderr=stderr) + return stdout.getvalue() except CommandFailedError: if 'no such file or directory' in stderr.getvalue().lower(): return None raise + def _get_global_id(self): + try: + p = self.run_shell_payload("getfattr --only-values -n ceph.client_id .", stdout=StringIO()) + v = p.stdout.getvalue() + prefix = "client" + assert v.startswith(prefix) + return int(v[len(prefix):]) + except CommandFailedError: + # Probably this fallback can be deleted in a few releases when the kernel xattr is widely available. + log.debug("Falling back to messy global_id lookup via /sys...") + + pyscript = dedent(""" + import glob + import os + import json + + def get_id_to_dir(): + result = {} + for dir in glob.glob("/sys/kernel/debug/ceph/*"): + mds_sessions_lines = open(os.path.join(dir, "mds_sessions")).readlines() + global_id = mds_sessions_lines[0].split()[1].strip('"') + client_id = mds_sessions_lines[1].split()[1].strip('"') + result[client_id] = global_id + return result + print(json.dumps(get_id_to_dir())) + """) + + output = self.client_remote.sh([ + 'sudo', 'python3', '-c', pyscript + ], timeout=(5*60)) + client_id_to_global_id = json.loads(output) + + try: + return client_id_to_global_id[self.client_id] + except KeyError: + log.error("Client id '{0}' debug dir not found (clients seen were: {1})".format( + self.client_id, ",".join(client_id_to_global_id.keys()) + )) + raise + def get_global_id(self): """ Look up the CephFS client ID for this mount, using debugfs. @@ -230,11 +243,7 @@ assert self.mounted - mds_sessions = self.read_debug_file("mds_sessions") - assert mds_sessions - - lines = mds_sessions.split("\n") - return int(lines[0].split()[1]) + return self._get_global_id() @property def _global_addr(self): diff -Nru ceph-16.2.5/qa/tasks/cephfs/mount.py ceph-16.2.6/qa/tasks/cephfs/mount.py --- ceph-16.2.5/qa/tasks/cephfs/mount.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/mount.py 2021-09-16 14:27:19.000000000 +0000 @@ -12,7 +12,7 @@ from IPy import IP from teuthology.contextutil import safe_while -from teuthology.misc import get_file, sudo_write_file +from teuthology.misc import get_file, write_file from teuthology.orchestra import run from teuthology.orchestra.run import CommandFailedError, ConnectionLostError, Raw @@ -590,7 +590,7 @@ for suffix in self.test_files: log.info("Creating file {0}".format(suffix)) self.client_remote.run(args=[ - 'sudo', 'touch', os.path.join(self.hostfs_mntpt, suffix) + 'touch', os.path.join(self.hostfs_mntpt, suffix) ]) def test_create_file(self, filename='testfile', dirname=None, user=None, @@ -604,7 +604,7 @@ for suffix in self.test_files: log.info("Checking file {0}".format(suffix)) r = self.client_remote.run(args=[ - 'sudo', 'ls', os.path.join(self.hostfs_mntpt, suffix) + 'ls', os.path.join(self.hostfs_mntpt, suffix) ], check_status=False) if r.exitstatus != 0: raise RuntimeError("Expected file {0} not found".format(suffix)) @@ -617,7 +617,7 @@ if path.find(self.hostfs_mntpt) == -1: path = os.path.join(self.hostfs_mntpt, path) - sudo_write_file(self.client_remote, path, data) + write_file(self.client_remote, path, data) if perms: self.run_shell(args=f'chmod {perms} {path}') @@ -629,7 +629,7 @@ if path.find(self.hostfs_mntpt) == -1: path = os.path.join(self.hostfs_mntpt, path) - return self.run_shell(args=['sudo', 'cat', path], omit_sudo=False).\ + return self.run_shell(args=['cat', path]).\ stdout.getvalue().strip() def create_destroy(self): @@ -638,34 +638,36 @@ filename = "{0} {1}".format(datetime.datetime.now(), self.client_id) log.debug("Creating test file {0}".format(filename)) self.client_remote.run(args=[ - 'sudo', 'touch', os.path.join(self.hostfs_mntpt, filename) + 'touch', os.path.join(self.hostfs_mntpt, filename) ]) log.debug("Deleting test file {0}".format(filename)) self.client_remote.run(args=[ - 'sudo', 'rm', '-f', os.path.join(self.hostfs_mntpt, filename) + 'rm', '-f', os.path.join(self.hostfs_mntpt, filename) ]) - def _run_python(self, pyscript, py_version='python3'): - return self.client_remote.run( - args=['sudo', 'adjust-ulimits', 'daemon-helper', 'kill', - py_version, '-c', pyscript], wait=False, stdin=run.PIPE, - stdout=StringIO()) + def _run_python(self, pyscript, py_version='python3', sudo=False): + args = [] + if sudo: + args.append('sudo') + args += ['adjust-ulimits', 'daemon-helper', 'kill', py_version, '-c', pyscript] + return self.client_remote.run(args=args, wait=False, stdin=run.PIPE, stdout=StringIO()) - def run_python(self, pyscript, py_version='python3'): - p = self._run_python(pyscript, py_version) + def run_python(self, pyscript, py_version='python3', sudo=False): + p = self._run_python(pyscript, py_version, sudo=sudo) p.wait() return p.stdout.getvalue().strip() - def run_shell(self, args, omit_sudo=True, timeout=900, **kwargs): + def run_shell(self, args, timeout=900, **kwargs): args = args.split() if isinstance(args, str) else args - # XXX: all commands ran with CephFS mount as CWD must be executed with - # superuser privileges when tests are being run using teuthology. - if args[0] != 'sudo': - args.insert(0, 'sudo') + kwargs.pop('omit_sudo', False) + sudo = kwargs.pop('sudo', False) cwd = kwargs.pop('cwd', self.mountpoint) stdout = kwargs.pop('stdout', StringIO()) stderr = kwargs.pop('stderr', StringIO()) + if sudo: + args.insert(0, 'sudo') + return self.client_remote.run(args=args, cwd=cwd, timeout=timeout, stdout=stdout, stderr=stderr, **kwargs) def run_shell_payload(self, payload, **kwargs): @@ -810,7 +812,7 @@ i = 0 while i < timeout: r = self.client_remote.run(args=[ - 'sudo', 'ls', os.path.join(self.hostfs_mntpt, basename) + 'stat', os.path.join(self.hostfs_mntpt, basename) ], check_status=False) if r.exitstatus == 0: log.debug("File {0} became visible from {1} after {2}s".format( @@ -908,7 +910,7 @@ log.info("check lock on file {0}".format(basename)) self.client_remote.run(args=[ - 'sudo', 'python3', '-c', pyscript + 'python3', '-c', pyscript ]) def write_background(self, basename="background_file", loop=False): @@ -969,6 +971,7 @@ def validate_test_pattern(self, filename, size): log.info("Validating {0} bytes from {1}".format(size, filename)) + # Use sudo because cephfs-data-scan may recreate the file with owner==root return self.run_python(dedent(""" import zlib path = "{path}" @@ -985,7 +988,7 @@ """.format( path=os.path.join(self.hostfs_mntpt, filename), size=size - ))) + )), sudo=True) def open_n_background(self, fs_path, count): """ @@ -1099,7 +1102,7 @@ def lstat(self, fs_path, follow_symlinks=False, wait=True): return self.stat(fs_path, follow_symlinks=False, wait=True) - def stat(self, fs_path, follow_symlinks=True, wait=True): + def stat(self, fs_path, follow_symlinks=True, wait=True, **kwargs): """ stat a file, and return the result as a dictionary like this: { @@ -1139,7 +1142,7 @@ dict([(a, getattr(s, a)) for a in attrs]), indent=2)) """).format(stat_call=stat_call) - proc = self._run_python(pyscript) + proc = self._run_python(pyscript, **kwargs) if wait: proc.wait() return json.loads(proc.stdout.getvalue().strip()) @@ -1205,7 +1208,7 @@ proc.wait() return int(proc.stdout.getvalue().strip()) - def ls(self, path=None): + def ls(self, path=None, **kwargs): """ Wrap ls: return a list of strings """ @@ -1213,7 +1216,7 @@ if path: cmd.append(path) - ls_text = self.run_shell(cmd).stdout.getvalue().strip() + ls_text = self.run_shell(cmd, **kwargs).stdout.getvalue().strip() if ls_text: return ls_text.split("\n") @@ -1222,7 +1225,7 @@ # gives you [''] instead of [] return [] - def setfattr(self, path, key, val): + def setfattr(self, path, key, val, **kwargs): """ Wrap setfattr. @@ -1231,16 +1234,16 @@ :param val: xattr value :return: None """ - self.run_shell(["setfattr", "-n", key, "-v", val, path]) + self.run_shell(["setfattr", "-n", key, "-v", val, path], **kwargs) - def getfattr(self, path, attr): + def getfattr(self, path, attr, **kwargs): """ Wrap getfattr: return the values of a named xattr on one file, or None if the attribute is not found. :return: a string """ - p = self.run_shell(["getfattr", "--only-values", "-n", attr, path], wait=False) + p = self.run_shell(["getfattr", "--only-values", "-n", attr, path], wait=False, **kwargs) try: p.wait() except CommandFailedError as e: diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_admin.py ceph-16.2.6/qa/tasks/cephfs/test_admin.py --- ceph-16.2.5/qa/tasks/cephfs/test_admin.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_admin.py 2021-09-16 14:27:19.000000000 +0000 @@ -1,4 +1,7 @@ +import errno import json +import logging +import time import uuid from io import StringIO from os.path import join as os_path_join @@ -10,6 +13,7 @@ from tasks.cephfs.fuse_mount import FuseMount from tasks.cephfs.caps_helper import CapsHelper +log = logging.getLogger(__name__) class TestAdminCommands(CephFSTestCase): """ @@ -17,7 +21,7 @@ """ CLIENTS_REQUIRED = 1 - MDSS_REQUIRED = 1 + MDSS_REQUIRED = 3 def test_fsnames_can_only_by_goodchars(self): n = 'test_fsnames_can_only_by_goodchars' @@ -84,7 +88,8 @@ """ pool_name = "foo" mon_cmd = self.fs.mon_manager.raw_cluster_cmd - mon_cmd('osd', 'pool', 'create', pool_name, str(self.fs.pgs_per_fs_pool)) + mon_cmd('osd', 'pool', 'create', pool_name, '--pg_num_min', + str(self.fs.pg_num_min)) # Check whether https://tracker.ceph.com/issues/43061 is fixed mon_cmd('osd', 'pool', 'application', 'enable', pool_name, 'cephfs') self.fs.add_data_pool(pool_name, create=False) @@ -187,13 +192,150 @@ pool_names = [fs_name+'-'+key for key in keys] mon_cmd = self.fs.mon_manager.raw_cluster_cmd for p in pool_names: - mon_cmd('osd', 'pool', 'create', p, str(self.fs.pgs_per_fs_pool)) + mon_cmd('osd', 'pool', 'create', p, '--pg_num_min', str(self.fs.pg_num_min)) mon_cmd('osd', 'pool', 'application', 'enable', p, 'cephfs') mon_cmd('fs', 'new', fs_name, pool_names[0], pool_names[1]) for i in range(2): self._check_pool_application_metadata_key_value( pool_names[i], 'cephfs', keys[i], fs_name) + def test_fs_new_with_specific_id(self): + """ + That a file system can be created with a specific ID. + """ + fs_name = "test_fs_specific_id" + fscid = 100 + keys = ['metadata', 'data'] + pool_names = [fs_name+'-'+key for key in keys] + for p in pool_names: + self.run_cluster_cmd(f'osd pool create {p}') + self.run_cluster_cmd(f'fs new {fs_name} {pool_names[0]} {pool_names[1]} --fscid {fscid} --force') + self.fs.status().get_fsmap(fscid) + for i in range(2): + self._check_pool_application_metadata_key_value(pool_names[i], 'cephfs', keys[i], fs_name) + + def test_fs_new_with_specific_id_idempotency(self): + """ + That command to create file system with specific ID is idempotent. + """ + fs_name = "test_fs_specific_id" + fscid = 100 + keys = ['metadata', 'data'] + pool_names = [fs_name+'-'+key for key in keys] + for p in pool_names: + self.run_cluster_cmd(f'osd pool create {p}') + self.run_cluster_cmd(f'fs new {fs_name} {pool_names[0]} {pool_names[1]} --fscid {fscid} --force') + self.run_cluster_cmd(f'fs new {fs_name} {pool_names[0]} {pool_names[1]} --fscid {fscid} --force') + self.fs.status().get_fsmap(fscid) + + def test_fs_new_with_specific_id_fails_without_force_flag(self): + """ + That command to create file system with specific ID fails without '--force' flag. + """ + fs_name = "test_fs_specific_id" + fscid = 100 + keys = ['metadata', 'data'] + pool_names = [fs_name+'-'+key for key in keys] + for p in pool_names: + self.run_cluster_cmd(f'osd pool create {p}') + try: + self.run_cluster_cmd(f'fs new {fs_name} {pool_names[0]} {pool_names[1]} --fscid {fscid}') + except CommandFailedError as ce: + self.assertEqual(ce.exitstatus, errno.EINVAL, + "invalid error code on creating a file system with specifc ID without --force flag") + else: + self.fail("expected creating file system with specific ID without '--force' flag to fail") + + def test_fs_new_with_specific_id_fails_already_in_use(self): + """ + That creating file system with ID already in use fails. + """ + fs_name = "test_fs_specific_id" + # file system ID already in use + fscid = self.fs.status().map['filesystems'][0]['id'] + keys = ['metadata', 'data'] + pool_names = [fs_name+'-'+key for key in keys] + for p in pool_names: + self.run_cluster_cmd(f'osd pool create {p}') + try: + self.run_cluster_cmd(f'fs new {fs_name} {pool_names[0]} {pool_names[1]} --fscid {fscid} --force') + except CommandFailedError as ce: + self.assertEqual(ce.exitstatus, errno.EINVAL, + "invalid error code on creating a file system with specifc ID that is already in use") + else: + self.fail("expected creating file system with ID already in use to fail") + + +class TestDump(CephFSTestCase): + CLIENTS_REQUIRED = 0 + MDSS_REQUIRED = 1 + + def test_fs_dump_epoch(self): + """ + That dumping a specific epoch works. + """ + + status1 = self.fs.status() + status2 = self.fs.status(epoch=status1["epoch"]-1) + self.assertEqual(status1["epoch"], status2["epoch"]+1) + + def test_fsmap_trim(self): + """ + That the fsmap is trimmed normally. + """ + + paxos_service_trim_min = 25 + self.config_set('mon', 'paxos_service_trim_min', paxos_service_trim_min) + mon_max_mdsmap_epochs = 20 + self.config_set('mon', 'mon_max_mdsmap_epochs', mon_max_mdsmap_epochs) + + status = self.fs.status() + epoch = status["epoch"] + + # for N mutations + mutations = paxos_service_trim_min + mon_max_mdsmap_epochs + b = False + for i in range(mutations): + self.fs.set_joinable(b) + b = not b + + time.sleep(10) # for tick/compaction + + try: + self.fs.status(epoch=epoch) + except CommandFailedError as e: + self.assertEqual(e.exitstatus, errno.ENOENT, "invalid error code when trying to fetch FSMap that was trimmed") + else: + self.fail("trimming did not occur as expected") + + def test_fsmap_force_trim(self): + """ + That the fsmap is trimmed forcefully. + """ + + status = self.fs.status() + epoch = status["epoch"] + + paxos_service_trim_min = 1 + self.config_set('mon', 'paxos_service_trim_min', paxos_service_trim_min) + mon_mds_force_trim_to = epoch+1 + self.config_set('mon', 'mon_mds_force_trim_to', mon_mds_force_trim_to) + + # force a new fsmap + self.fs.set_joinable(False) + time.sleep(10) # for tick/compaction + + status = self.fs.status() + log.debug(f"new epoch is {status['epoch']}") + self.fs.status(epoch=epoch+1) # epoch+1 is not trimmed, may not == status["epoch"] + + try: + self.fs.status(epoch=epoch) + except CommandFailedError as e: + self.assertEqual(e.exitstatus, errno.ENOENT, "invalid error code when trying to fetch FSMap that was trimmed") + else: + self.fail("trimming did not occur as expected") + class TestRequiredClientFeatures(CephFSTestCase): CLIENTS_REQUIRED = 0 MDSS_REQUIRED = 1 @@ -265,6 +407,141 @@ p = self.fs.required_client_features('rm', '1', stderr=StringIO()) self.assertIn("removed feature 'reserved' from required_client_features", p.stderr.getvalue()) +class TestCompatCommands(CephFSTestCase): + """ + """ + + CLIENTS_REQUIRED = 0 + MDSS_REQUIRED = 3 + + def test_add_compat(self): + """ + Test adding a compat. + """ + + self.fs.fail() + self.fs.add_compat(63, 'placeholder') + mdsmap = self.fs.get_mds_map() + self.assertIn("feature_63", mdsmap['compat']['compat']) + + def test_add_incompat(self): + """ + Test adding an incompat. + """ + + self.fs.fail() + self.fs.add_incompat(63, 'placeholder') + mdsmap = self.fs.get_mds_map() + log.info(f"{mdsmap}") + self.assertIn("feature_63", mdsmap['compat']['incompat']) + + def test_rm_compat(self): + """ + Test removing a compat. + """ + + self.fs.fail() + self.fs.add_compat(63, 'placeholder') + self.fs.rm_compat(63) + mdsmap = self.fs.get_mds_map() + self.assertNotIn("feature_63", mdsmap['compat']['compat']) + + def test_rm_incompat(self): + """ + Test removing an incompat. + """ + + self.fs.fail() + self.fs.add_incompat(63, 'placeholder') + self.fs.rm_incompat(63) + mdsmap = self.fs.get_mds_map() + self.assertNotIn("feature_63", mdsmap['compat']['incompat']) + + def test_standby_compat(self): + """ + That adding a compat does not prevent standbys from joining. + """ + + self.fs.fail() + self.fs.add_compat(63, "placeholder") + self.fs.set_joinable() + self.fs.wait_for_daemons() + mdsmap = self.fs.get_mds_map() + self.assertIn("feature_63", mdsmap['compat']['compat']) + + def test_standby_incompat_reject(self): + """ + That adding an incompat feature prevents incompatible daemons from joining. + """ + + self.fs.fail() + self.fs.add_incompat(63, "placeholder") + self.fs.set_joinable() + try: + self.fs.wait_for_daemons(timeout=60) + except RuntimeError as e: + if "Timed out waiting for MDS daemons to become healthy" in str(e): + pass + else: + raise + else: + self.fail() + + def test_standby_incompat_upgrade(self): + """ + That an MDS can upgrade the compat of a fs. + """ + + self.fs.fail() + self.fs.rm_incompat(1) + self.fs.set_joinable() + self.fs.wait_for_daemons() + mdsmap = self.fs.get_mds_map() + self.assertIn("feature_1", mdsmap['compat']['incompat']) + + def test_standby_replay_not_upgradeable(self): + """ + That the mons will not upgrade the MDSMap compat if standby-replay is + enabled. + """ + + self.fs.fail() + self.fs.rm_incompat(1) + self.fs.set_allow_standby_replay(True) + self.fs.set_joinable() + try: + self.fs.wait_for_daemons(timeout=60) + except RuntimeError as e: + if "Timed out waiting for MDS daemons to become healthy" in str(e): + pass + else: + raise + else: + self.fail() + + def test_standby_incompat_reject_multifs(self): + """ + Like test_standby_incompat_reject but with a second fs. + """ + + fs2 = self.mds_cluster.newfs(name="cephfs2", create=True) + fs2.fail() + fs2.add_incompat(63, 'placeholder') + fs2.set_joinable() + try: + fs2.wait_for_daemons(timeout=60) + except RuntimeError as e: + if "Timed out waiting for MDS daemons to become healthy" in str(e): + pass + else: + raise + else: + self.fail() + # did self.fs lose MDS or standbys suicide? + self.fs.wait_for_daemons() + mdsmap = fs2.get_mds_map() + self.assertIn("feature_63", mdsmap['compat']['incompat']) + class TestConfigCommands(CephFSTestCase): """ Test that daemons and clients respond to the otherwise rarely-used diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_cap_flush.py ceph-16.2.6/qa/tasks/cephfs/test_cap_flush.py --- ceph-16.2.5/qa/tasks/cephfs/test_cap_flush.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_cap_flush.py 2021-09-16 14:27:19.000000000 +0000 @@ -41,10 +41,10 @@ fd = os.open("{1}", os.O_CREAT | os.O_RDWR, 0o644) os.fchmod(fd, 0o640) """).format(dir_path, file_name) - self.mount_a.run_python(py_script) + self.mount_a.run_python(py_script, sudo=True) # Modify file mode by different user. ceph-fuse will send a setattr request - self.mount_a.run_shell(["chmod", "600", file_path], wait=False) + self.mount_a.run_shell(["chmod", "600", file_path], wait=False, sudo=True) time.sleep(10) diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_cephfs_shell.py ceph-16.2.6/qa/tasks/cephfs/test_cephfs_shell.py --- ceph-16.2.5/qa/tasks/cephfs/test_cephfs_shell.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_cephfs_shell.py 2021-09-16 14:27:19.000000000 +0000 @@ -137,7 +137,7 @@ scriptfile.write(script) # copy script to the machine running cephfs-shell. mount_x.client_remote.put_file(scriptpath, scriptpath) - mount_x.run_shell('chmod 755 ' + scriptpath) + mount_x.run_shell_payload(f"chmod 755 {scriptpath}") args = ["cephfs-shell", '-b', scriptpath] if shell_conf_path: @@ -321,8 +321,7 @@ size = i + 1 ofarg = 'of=' + path.join(tempdir, file_) bsarg = 'bs=' + str(size) + 'M' - self.mount_a.run_shell(['dd', 'if=/dev/urandom', ofarg, bsarg, - 'count=1']) + self.mount_a.run_shell_payload(f"dd if=/dev/urandom {ofarg} {bsarg} count=1") self.run_cephfs_shell_cmd('put ' + tempdir) for file_ in files: @@ -332,16 +331,15 @@ self.mount_a.stat(path.join(self.mount_a.mountpoint, tempdirname, file_)) - self.mount_a.run_shell(['rm', '-rf', tempdir]) + self.mount_a.run_shell_payload(f"rm -rf {tempdir}") self.run_cephfs_shell_cmd('get ' + tempdirname) pwd = self.get_cephfs_shell_cmd_output('!pwd') for file_ in files: if file_ == tempdirname: - self.mount_a.run_shell('stat ' + path.join(pwd, file_)) + self.mount_a.run_shell_payload(f"stat {path.join(pwd, file_)}") else: - self.mount_a.run_shell('stat ' + path.join(pwd, tempdirname, - file_)) + self.mount_a.run_shell_payload(f"stat {path.join(pwd, tempdirname, file_)}") def test_get_with_target_name(self): """ @@ -488,7 +486,7 @@ to root directory. """ path = 'dir1/dir2/dir3' - self.mount_a.run_shell('mkdir -p ' + path) + self.mount_a.run_shell_payload(f"mkdir -p {path}") expected_cwd = '/' script = 'cd {}\ncd\ncwd\n'.format(path) @@ -501,7 +499,7 @@ to the path passed in the argument. """ path = 'dir1/dir2/dir3' - self.mount_a.run_shell('mkdir -p ' + path) + self.mount_a.run_shell_payload(f"mkdir -p {path}") expected_cwd = '/dir1/dir2/dir3' script = 'cd {}\ncwd\n'.format(path) @@ -514,8 +512,7 @@ def test_du_works_for_regfiles(self): regfilename = 'some_regfile' regfile_abspath = path.join(self.mount_a.mountpoint, regfilename) - self.mount_a.client_remote.write_file(regfile_abspath, - 'somedata', sudo=True) + self.mount_a.client_remote.write_file(regfile_abspath, 'somedata') size = humansize(self.mount_a.stat(regfile_abspath)['st_size']) expected_output = r'{}{}{}'.format(size, " +", regfilename) @@ -528,9 +525,8 @@ dir_abspath = path.join(self.mount_a.mountpoint, dirname) regfilename = 'some_regfile' regfile_abspath = path.join(dir_abspath, regfilename) - self.mount_a.run_shell('mkdir ' + dir_abspath) - self.mount_a.client_remote.write_file(regfile_abspath, - 'somedata', sudo=True) + self.mount_a.run_shell_payload(f"mkdir {dir_abspath}") + self.mount_a.client_remote.write_file(regfile_abspath, 'somedata') # XXX: we stat `regfile_abspath` here because ceph du reports a non-empty # directory's size as sum of sizes of all files under it. @@ -544,7 +540,7 @@ def test_du_works_for_empty_dirs(self): dirname = 'some_directory' dir_abspath = path.join(self.mount_a.mountpoint, dirname) - self.mount_a.run_shell('mkdir ' + dir_abspath) + self.mount_a.run_shell_payload(f"mkdir {dir_abspath}") size = humansize(self.mount_a.stat(dir_abspath)['st_size']) expected_output = r'{}{}{}'.format(size, " +", dirname) @@ -555,12 +551,10 @@ def test_du_works_for_hardlinks(self): regfilename = 'some_regfile' regfile_abspath = path.join(self.mount_a.mountpoint, regfilename) - self.mount_a.client_remote.write_file(regfile_abspath, - 'somedata', sudo=True) + self.mount_a.client_remote.write_file(regfile_abspath, 'somedata') hlinkname = 'some_hardlink' hlink_abspath = path.join(self.mount_a.mountpoint, hlinkname) - self.mount_a.run_shell(['sudo', 'ln', regfile_abspath, - hlink_abspath], omit_sudo=False) + self.mount_a.run_shell_payload(f"ln {regfile_abspath} {hlink_abspath}") size = humansize(self.mount_a.stat(hlink_abspath)['st_size']) expected_output = r'{}{}{}'.format(size, " +", hlinkname) @@ -571,11 +565,10 @@ def test_du_works_for_softlinks_to_files(self): regfilename = 'some_regfile' regfile_abspath = path.join(self.mount_a.mountpoint, regfilename) - self.mount_a.client_remote.write_file(regfile_abspath, - 'somedata', sudo=True) + self.mount_a.client_remote.write_file(regfile_abspath, 'somedata') slinkname = 'some_softlink' slink_abspath = path.join(self.mount_a.mountpoint, slinkname) - self.mount_a.run_shell(['ln', '-s', regfile_abspath, slink_abspath]) + self.mount_a.run_shell_payload(f"ln -s {regfile_abspath} {slink_abspath}") size = humansize(self.mount_a.lstat(slink_abspath)['st_size']) expected_output = r'{}{}{}'.format((size), " +", slinkname) @@ -586,10 +579,10 @@ def test_du_works_for_softlinks_to_dirs(self): dirname = 'some_directory' dir_abspath = path.join(self.mount_a.mountpoint, dirname) - self.mount_a.run_shell('mkdir ' + dir_abspath) + self.mount_a.run_shell_payload(f"mkdir {dir_abspath}") slinkname = 'some_softlink' slink_abspath = path.join(self.mount_a.mountpoint, slinkname) - self.mount_a.run_shell(['ln', '-s', dir_abspath, slink_abspath]) + self.mount_a.run_shell_payload(f"ln -s {dir_abspath} {slink_abspath}") size = humansize(self.mount_a.lstat(slink_abspath)['st_size']) expected_output = r'{}{}{}'.format(size, " +", slinkname) @@ -612,11 +605,11 @@ slink_abspath = path.join(self.mount_a.mountpoint, slinkname) slink2_abspath = path.join(self.mount_a.mountpoint, slink2name) - self.mount_a.run_shell('mkdir ' + dir_abspath) - self.mount_a.run_shell('touch ' + regfile_abspath) - self.mount_a.run_shell(['ln', regfile_abspath, hlink_abspath]) - self.mount_a.run_shell(['ln', '-s', regfile_abspath, slink_abspath]) - self.mount_a.run_shell(['ln', '-s', dir_abspath, slink2_abspath]) + self.mount_a.run_shell_payload(f"mkdir {dir_abspath}") + self.mount_a.run_shell_payload(f"touch {regfile_abspath}") + self.mount_a.run_shell_payload(f"ln {regfile_abspath} {hlink_abspath}") + self.mount_a.run_shell_payload(f"ln -s {regfile_abspath} {slink_abspath}") + self.mount_a.run_shell_payload(f"ln -s {dir_abspath} {slink2_abspath}") dir2_name = 'dir2' dir21_name = 'dir21' @@ -624,13 +617,11 @@ dir2_abspath = path.join(self.mount_a.mountpoint, dir2_name) dir21_abspath = path.join(dir2_abspath, dir21_name) regfile121_abspath = path.join(dir21_abspath, regfile121_name) - self.mount_a.run_shell('mkdir -p ' + dir21_abspath) - self.mount_a.run_shell('touch ' + regfile121_abspath) + self.mount_a.run_shell_payload(f"mkdir -p {dir21_abspath}") + self.mount_a.run_shell_payload(f"touch {regfile121_abspath}") - self.mount_a.client_remote.write_file(regfile_abspath, - 'somedata', sudo=True) - self.mount_a.client_remote.write_file(regfile121_abspath, - 'somemoredata', sudo=True) + self.mount_a.client_remote.write_file(regfile_abspath, 'somedata') + self.mount_a.client_remote.write_file(regfile121_abspath, 'somemoredata') # TODO: is there a way to trigger/force update ceph.dir.rbytes? # wait so that attr ceph.dir.rbytes gets a chance to be updated. @@ -731,7 +722,7 @@ def test_df_for_valid_directory(self): dir_name = 'dir1' - mount_output = self.mount_a.run_shell('mkdir ' + dir_name) + mount_output = self.mount_a.run_shell_payload(f"mkdir {dir_name}") log.info("cephfs-shell mount output:\n{}".format(mount_output)) self.validate_df(dir_name) @@ -799,10 +790,10 @@ def test_exceed_file_limit(self): self.test_set() dir_abspath = path.join(self.mount_a.mountpoint, self.dir_name) - self.mount_a.run_shell('touch '+dir_abspath+'/file1') + self.mount_a.run_shell_payload(f"touch {dir_abspath}/file1") file2 = path.join(dir_abspath, "file2") try: - self.mount_a.run_shell('touch '+file2) + self.mount_a.run_shell_payload(f"touch {file2}") raise Exception("Something went wrong!! File creation should have failed") except CommandFailedError: # Test should pass as file quota set to 2 @@ -818,8 +809,7 @@ file_abspath = path.join(dir_abspath, filename) try: # Write should fail as bytes quota is set to 6 - self.mount_a.client_remote.write_file(file_abspath, - 'Disk raise Exception', sudo=True) + self.mount_a.client_remote.write_file(file_abspath, 'Disk raise Exception') raise Exception("Write should have failed") except CommandFailedError: # Test should pass only when write command fails @@ -924,8 +914,8 @@ for (file_size, file_name) in zip(file_sizes, file_names): temp_file = self.mount_a.client_remote.mktemp(file_name) - self.mount_a.run_shell(f"fallocate -l {file_size} {temp_file}") - self.mount_a.run_shell(f'mv {temp_file} ./') + self.mount_a.run_shell_payload(f"fallocate -l {file_size} {temp_file}") + self.mount_a.run_shell_payload(f'mv {temp_file} ./') ls_H_output = self.get_cephfs_shell_cmd_output(['ls', '-lH']) diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_client_recovery.py ceph-16.2.6/qa/tasks/cephfs/test_client_recovery.py --- ceph-16.2.5/qa/tasks/cephfs/test_client_recovery.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_client_recovery.py 2021-09-16 14:27:19.000000000 +0000 @@ -135,9 +135,11 @@ # ================= # Check that if I stop an MDS and a client goes away, the MDS waits # for the reconnect period - self.fs.fail() mount_a_client_id = self.mount_a.get_global_id() + + self.fs.fail() + self.mount_a.umount_wait(force=True) self.fs.set_joinable() @@ -508,9 +510,8 @@ self.assertEqual(current_readdirs, initial_readdirs); mount_b_gid = self.mount_b.get_global_id() - mount_b_pid = self.mount_b.get_client_pid() # stop ceph-fuse process of mount_b - self.mount_b.client_remote.run(args=["sudo", "kill", "-STOP", mount_b_pid]) + self.mount_b.suspend_netns() self.assert_session_state(mount_b_gid, "open") time.sleep(session_timeout * 1.5) # Long enough for MDS to consider session stale @@ -519,7 +520,7 @@ self.assert_session_state(mount_b_gid, "stale") # resume ceph-fuse process of mount_b - self.mount_b.client_remote.run(args=["sudo", "kill", "-CONT", mount_b_pid]) + self.mount_b.resume_netns() # Is the new file visible from mount_b? (caps become invalid after session stale) self.mount_b.run_shell(["ls", "testdir/file2"]) @@ -615,10 +616,10 @@ self.mount_a.umount_wait() if isinstance(self.mount_a, FuseMount): - self.mount_a.mount(mntopts=['--client_reconnect_stale=1', '--fuse_disable_pagecache=1']) + self.mount_a.mount_wait(mntopts=['--client_reconnect_stale=1', '--fuse_disable_pagecache=1']) else: try: - self.mount_a.mount(mntopts=['recover_session=clean']) + self.mount_a.mount_wait(mntopts=['recover_session=clean']) except CommandFailedError: self.mount_a.kill_cleanup() self.skipTest("Not implemented in current kernel") @@ -682,7 +683,7 @@ raise RuntimeError("read() failed to raise error") """).format(path=path) rproc = self.mount_a.client_remote.run( - args=['sudo', 'python3', '-c', pyscript], + args=['python3', '-c', pyscript], wait=False, stdin=run.PIPE, stdout=run.PIPE) rproc.stdout.readline() diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_data_scan.py ceph-16.2.6/qa/tasks/cephfs/test_data_scan.py --- ceph-16.2.5/qa/tasks/cephfs/test_data_scan.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_data_scan.py 2021-09-16 14:27:19.000000000 +0000 @@ -82,8 +82,8 @@ self._initial_state = self._mount.stat("subdir/sixmegs") def validate(self): - self._mount.run_shell(["ls", "subdir"]) - st = self._mount.stat("subdir/sixmegs") + self._mount.run_shell(["ls", "subdir"], sudo=True) + st = self._mount.stat("subdir/sixmegs", sudo=True) self.assert_equal(st['st_size'], self._initial_state['st_size']) return self._errors @@ -104,8 +104,8 @@ pass def validate(self): - self.assert_equal(self._mount.ls(), ["subdir_alpha"]) - st = self._mount.stat("subdir_alpha/sixmegs") + self.assert_equal(self._mount.ls(sudo=True), ["subdir_alpha"]) + st = self._mount.stat("subdir_alpha/sixmegs", sudo=True) self.assert_equal(st['st_size'], self._initial_state['st_size']) return self._errors @@ -124,9 +124,9 @@ ino_name = "%x" % self._initial_state["st_ino"] # The inode should be linked into lost+found because we had no path for it - self.assert_equal(self._mount.ls(), ["lost+found"]) - self.assert_equal(self._mount.ls("lost+found"), [ino_name]) - st = self._mount.stat("lost+found/{ino_name}".format(ino_name=ino_name)) + self.assert_equal(self._mount.ls(sudo=True), ["lost+found"]) + self.assert_equal(self._mount.ls("lost+found", sudo=True), [ino_name]) + st = self._mount.stat(f"lost+found/{ino_name}", sudo=True) # We might not have got the name or path, but we should still get the size self.assert_equal(st['st_size'], self._initial_state['st_size']) @@ -200,7 +200,7 @@ # The unflushed file should have been recovered into lost+found without # the correct layout: read back junk ino_name = "%x" % self._initial_state["unflushed_ino"] - self.assert_equal(self._mount.ls("lost+found"), [ino_name]) + self.assert_equal(self._mount.ls("lost+found", sudo=True), [ino_name]) try: self._mount.validate_test_pattern(os.path.join("lost+found", ino_name), 1024 * 512) except CommandFailedError: @@ -259,8 +259,8 @@ self.assert_equal(len(root_files), 1) self.assert_equal(root_files[0] in ["grandfather", "grandmother"], True) winner = root_files[0] - st_opf = self._mount.stat("{0}/parent/orig_pos_file".format(winner)) - st_npf = self._mount.stat("{0}/parent/new_pos_file".format(winner)) + st_opf = self._mount.stat(f"{winner}/parent/orig_pos_file", sudo=True) + st_npf = self._mount.stat(f"{winner}/parent/new_pos_file", sudo=True) self.assert_equal(st_opf['st_size'], self._initial_state[0]['st_size']) self.assert_equal(st_npf['st_size'], self._initial_state[1]['st_size']) @@ -278,7 +278,8 @@ self._filesystem.rados(["rm", zeroth_id], pool=self._filesystem.get_data_pool_name()) def validate(self): - st = self._mount.stat("lost+found/{0:x}".format(self._initial_state['st_ino'])) + ino = self._initial_state['st_ino'] + st = self._mount.stat(f"lost+found/{ino:x}", sudo=True) self.assert_equal(st['st_size'], self._initial_state['st_size']) @@ -295,12 +296,11 @@ def validate(self): # Check we got the layout reconstructed properly - object_size = int(self._mount.getfattr( - "./datafile", "ceph.file.layout.object_size")) + object_size = int(self._mount.getfattr("./datafile", "ceph.file.layout.object_size", sudo=True)) self.assert_equal(object_size, 8388608) # Check we got the file size reconstructed properly - st = self._mount.stat("datafile") + st = self._mount.stat("datafile", sudo=True) self.assert_equal(st['st_size'], self._initial_state['st_size']) @@ -490,7 +490,9 @@ self.fs.set_joinable() self.fs.wait_for_daemons() self.mount_a.mount_wait() - out = self.mount_a.run_shell(["cat", "subdir/{0}".format(victim_dentry)]).stdout.getvalue().strip() + self.mount_a.run_shell(["ls", "-l", "subdir/"]) # debugging + # Use sudo because cephfs-data-scan will reinsert the dentry with root ownership, it can't know the real owner. + out = self.mount_a.run_shell_payload(f"cat subdir/{victim_dentry}", sudo=True).stdout.getvalue().strip() self.assertEqual(out, victim_dentry) # Finally, close the loop by checking our injected dentry survives a merge @@ -543,7 +545,7 @@ pgs_to_files[pgid].append(file_path) log.info("{0}: {1}".format(file_path, pgid)) - pg_count = self.fs.pgs_per_fs_pool + pg_count = self.fs.get_pool_pg_num(self.fs.get_data_pool_name()) for pg_n in range(0, pg_count): pg_str = "{0}.{1:x}".format(self.fs.get_data_pool_id(), pg_n) out = self.fs.data_scan(["pg_files", "mydir", pg_str]) diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_failover.py ceph-16.2.6/qa/tasks/cephfs/test_failover.py --- ceph-16.2.5/qa/tasks/cephfs/test_failover.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_failover.py 2021-09-16 14:27:19.000000000 +0000 @@ -650,14 +650,14 @@ fs_a, fs_b = self._setup_two() # Mount a client on fs_a - self.mount_a.mount(cephfs_name=fs_a.name) + self.mount_a.mount_wait(cephfs_name=fs_a.name) self.mount_a.write_n_mb("pad.bin", 1) self.mount_a.write_n_mb("test.bin", 2) a_created_ino = self.mount_a.path_to_ino("test.bin") self.mount_a.create_files() # Mount a client on fs_b - self.mount_b.mount(cephfs_name=fs_b.name) + self.mount_b.mount_wait(cephfs_name=fs_b.name) self.mount_b.write_n_mb("test.bin", 1) b_created_ino = self.mount_b.path_to_ino("test.bin") self.mount_b.create_files() diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_fragment.py ceph-16.2.6/qa/tasks/cephfs/test_fragment.py --- ceph-16.2.5/qa/tasks/cephfs/test_fragment.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_fragment.py 2021-09-16 14:27:19.000000000 +0000 @@ -297,7 +297,7 @@ self.mount_a.run_shell(["ln", "testdir1/{0}".format(i), "testdir2/"]) self.mount_a.umount_wait() - self.mount_a.mount() + self.mount_a.mount_wait() self.mount_a.wait_until_mounted() # flush journal and restart mds. after restart, testdir2 is not in mds' cache diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_full.py ceph-16.2.6/qa/tasks/cephfs/test_full.py --- ceph-16.2.5/qa/tasks/cephfs/test_full.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_full.py 2021-09-16 14:27:19.000000000 +0000 @@ -25,9 +25,8 @@ pool_capacity = None # type: Optional[int] fill_mb = None - # Subclasses define what fullness means to them def is_full(self): - raise NotImplementedError() + return self.fs.is_full() def setUp(self): CephFSTestCase.setUp(self) @@ -126,14 +125,14 @@ # how soon the cluster recognises its own fullness self.mount_a.write_n_mb("large_file_a", self.fill_mb // 2) try: - self.mount_a.write_n_mb("large_file_b", self.fill_mb // 2) + self.mount_a.write_n_mb("large_file_b", (self.fill_mb * 1.1) // 2) except CommandFailedError: log.info("Writing file B failed (full status happened already)") assert self.is_full() else: log.info("Writing file B succeeded (full status will happen soon)") self.wait_until_true(lambda: self.is_full(), - timeout=osd_mon_report_interval * 5) + timeout=osd_mon_report_interval * 120) # Attempting to write more data should give me ENOSPC with self.assertRaises(CommandFailedError) as ar: @@ -168,7 +167,7 @@ # * The MDS to purge the stray folder and execute object deletions # * The OSDs to inform the mon that they are no longer full self.wait_until_true(lambda: not self.is_full(), - timeout=osd_mon_report_interval * 5) + timeout=osd_mon_report_interval * 120) # Wait for the MDS to see the latest OSD map so that it will reliably # be applying the free space policy @@ -214,9 +213,13 @@ log.warning("This test may run rather slowly unless you decrease" "osd_mon_report_interval (5 is a good setting)!") + # set the object_size to 1MB to make the objects destributed more evenly + # among the OSDs to fix Tracker#45434 + file_layout = "stripe_unit=1048576 stripe_count=1 object_size=1048576" self.mount_a.run_python(template.format( fill_mb=self.fill_mb, file_path=file_path, + file_layout=file_layout, full_wait=full_wait, is_fuse=isinstance(self.mount_a, FuseMount) )) @@ -234,6 +237,7 @@ print("writing some data through which we expect to succeed") bytes = 0 f = os.open("{file_path}", os.O_WRONLY | os.O_CREAT) + os.setxattr("{file_path}", 'ceph.file.layout', b'{file_layout}') bytes += os.write(f, b'a' * 512 * 1024) os.fsync(f) print("fsync'ed data successfully, will now attempt to fill fs") @@ -305,6 +309,7 @@ print("writing some data through which we expect to succeed") bytes = 0 f = os.open("{file_path}", os.O_WRONLY | os.O_CREAT) + os.setxattr("{file_path}", 'ceph.file.layout', b'{file_layout}') bytes += os.write(f, b'a' * 4096) os.fsync(f) print("fsync'ed data successfully, will now attempt to fill fs") @@ -320,8 +325,13 @@ bytes += os.write(f, b'x' * 1024 * 1024) print("wrote bytes via buffered write, moving on to fsync") except OSError as e: - print("Unexpected error %s from write() instead of fsync()" % e) - raise + if {is_fuse}: + print("Unexpected error %s from write() instead of fsync()" % e) + raise + else: + print("Reached fullness after %.2f MB" % (bytes / (1024.0 * 1024.0))) + full = True + break try: os.fsync(f) @@ -373,9 +383,6 @@ self.fs.mon_manager.raw_cluster_cmd("osd", "pool", "set-quota", pool_name, "max_bytes", "{0}".format(self.pool_capacity)) - def is_full(self): - return self.fs.is_full() - class TestClusterFull(FullnessTestCase): """ @@ -388,13 +395,8 @@ super(TestClusterFull, self).setUp() if self.pool_capacity is None: - max_avail = self.fs.get_pool_df(self._data_pool_name())['max_avail'] - full_ratio = float(self.fs.get_config("mon_osd_full_ratio", service_type="mon")) - TestClusterFull.pool_capacity = int(max_avail * full_ratio) + TestClusterFull.pool_capacity = self.fs.get_pool_df(self._data_pool_name())['max_avail'] TestClusterFull.fill_mb = (self.pool_capacity // (1024 * 1024)) - def is_full(self): - return self.fs.is_full() - # Hide the parent class so that unittest.loader doesn't try to run it. del globals()['FullnessTestCase'] diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_mirroring.py ceph-16.2.6/qa/tasks/cephfs/test_mirroring.py --- ceph-16.2.5/qa/tasks/cephfs/test_mirroring.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_mirroring.py 2021-09-16 14:27:19.000000000 +0000 @@ -480,7 +480,7 @@ log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) # create a bunch of files in a directory to snap self.mount_a.run_shell(["mkdir", "d0"]) @@ -546,7 +546,7 @@ log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) # create a bunch of files in a directory to snap self.mount_a.run_shell(["mkdir", "d0"]) @@ -582,7 +582,7 @@ log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) # create a bunch of files in a directory to snap self.mount_a.run_shell(["mkdir", "d0"]) @@ -818,7 +818,7 @@ log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) # create a bunch of files w/ symbolic links in a directory to snap self.mount_a.run_shell(["mkdir", "d0"]) @@ -955,7 +955,7 @@ self.backup_fs.get_data_pool_name(), self.backup_fs.get_data_pool_name())) log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) repo = 'ceph-qa-suite' repo_dir = 'ceph_repo' @@ -1033,7 +1033,7 @@ self.backup_fs.get_data_pool_name(), self.backup_fs.get_data_pool_name())) log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) typs = deque(['reg', 'dir', 'sym']) def cleanup_and_create_with_type(dirname, fnames): @@ -1104,7 +1104,7 @@ self.backup_fs.get_data_pool_name(), self.backup_fs.get_data_pool_name())) log.debug(f'mounting filesystem {self.secondary_fs_name}') self.mount_b.umount_wait() - self.mount_b.mount(cephfs_name=self.secondary_fs_name) + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) repo = 'ceph-qa-suite' repo_dir = 'ceph_repo' @@ -1166,3 +1166,105 @@ raise RuntimeError('adding peer should fail') self.disable_mirroring(self.primary_fs_name, self.primary_fs_id) + + def test_cephfs_mirror_cancel_mirroring_and_readd(self): + """ + Test adding a directory path for synchronization post removal of already added directory paths + + ... to ensure that synchronization of the newly added directory path functions + as expected. Note that we schedule three (3) directories for mirroring to ensure + that all replayer threads (3 by default) in the mirror daemon are busy. + """ + log.debug('reconfigure client auth caps') + self.mds_cluster.mon_manager.raw_cluster_cmd_result( + 'auth', 'caps', "client.{0}".format(self.mount_b.client_id), + 'mds', 'allow rw', + 'mon', 'allow r', + 'osd', 'allow rw pool={0}, allow rw pool={1}'.format( + self.backup_fs.get_data_pool_name(), self.backup_fs.get_data_pool_name())) + + log.debug(f'mounting filesystem {self.secondary_fs_name}') + self.mount_b.umount_wait() + self.mount_b.mount_wait(cephfs_name=self.secondary_fs_name) + + # create a bunch of files in a directory to snap + self.mount_a.run_shell(["mkdir", "d0"]) + self.mount_a.run_shell(["mkdir", "d1"]) + self.mount_a.run_shell(["mkdir", "d2"]) + for i in range(4): + filename = f'file.{i}' + self.mount_a.write_n_mb(os.path.join('d0', filename), 1024) + self.mount_a.write_n_mb(os.path.join('d1', filename), 1024) + self.mount_a.write_n_mb(os.path.join('d2', filename), 1024) + + log.debug('enabling mirroring') + self.enable_mirroring(self.primary_fs_name, self.primary_fs_id) + log.debug('adding directory paths') + self.add_directory(self.primary_fs_name, self.primary_fs_id, '/d0') + self.add_directory(self.primary_fs_name, self.primary_fs_id, '/d1') + self.add_directory(self.primary_fs_name, self.primary_fs_id, '/d2') + self.peer_add(self.primary_fs_name, self.primary_fs_id, "client.mirror_remote@ceph", self.secondary_fs_name) + + # take snapshots + log.debug('taking snapshots') + self.mount_a.run_shell(["mkdir", "d0/.snap/snap0"]) + self.mount_a.run_shell(["mkdir", "d1/.snap/snap0"]) + self.mount_a.run_shell(["mkdir", "d2/.snap/snap0"]) + + time.sleep(10) + log.debug('checking snap in progress') + self.check_peer_snap_in_progress(self.primary_fs_name, self.primary_fs_id, + "client.mirror_remote@ceph", '/d0', 'snap0') + self.check_peer_snap_in_progress(self.primary_fs_name, self.primary_fs_id, + "client.mirror_remote@ceph", '/d1', 'snap0') + self.check_peer_snap_in_progress(self.primary_fs_name, self.primary_fs_id, + "client.mirror_remote@ceph", '/d2', 'snap0') + + log.debug('removing directories 1') + self.remove_directory(self.primary_fs_name, self.primary_fs_id, '/d0') + log.debug('removing directories 2') + self.remove_directory(self.primary_fs_name, self.primary_fs_id, '/d1') + log.debug('removing directories 3') + self.remove_directory(self.primary_fs_name, self.primary_fs_id, '/d2') + + log.debug('removing snapshots') + self.mount_a.run_shell(["rmdir", "d0/.snap/snap0"]) + self.mount_a.run_shell(["rmdir", "d1/.snap/snap0"]) + self.mount_a.run_shell(["rmdir", "d2/.snap/snap0"]) + + for i in range(4): + filename = f'file.{i}' + log.debug(f'deleting {filename}') + self.mount_a.run_shell(["rm", "-f", os.path.join('d0', filename)]) + self.mount_a.run_shell(["rm", "-f", os.path.join('d1', filename)]) + self.mount_a.run_shell(["rm", "-f", os.path.join('d2', filename)]) + + log.debug('creating new files...') + self.mount_a.create_n_files('d0/file', 50, sync=True) + self.mount_a.create_n_files('d1/file', 50, sync=True) + self.mount_a.create_n_files('d2/file', 50, sync=True) + + log.debug('adding directory paths') + self.add_directory(self.primary_fs_name, self.primary_fs_id, '/d0') + self.add_directory(self.primary_fs_name, self.primary_fs_id, '/d1') + self.add_directory(self.primary_fs_name, self.primary_fs_id, '/d2') + + log.debug('creating new snapshots...') + self.mount_a.run_shell(["mkdir", "d0/.snap/snap0"]) + self.mount_a.run_shell(["mkdir", "d1/.snap/snap0"]) + self.mount_a.run_shell(["mkdir", "d2/.snap/snap0"]) + + time.sleep(60) + self.check_peer_status(self.primary_fs_name, self.primary_fs_id, + "client.mirror_remote@ceph", '/d0', 'snap0', 1) + self.verify_snapshot('d0', 'snap0') + + self.check_peer_status(self.primary_fs_name, self.primary_fs_id, + "client.mirror_remote@ceph", '/d1', 'snap0', 1) + self.verify_snapshot('d1', 'snap0') + + self.check_peer_status(self.primary_fs_name, self.primary_fs_id, + "client.mirror_remote@ceph", '/d2', 'snap0', 1) + self.verify_snapshot('d2', 'snap0') + + self.disable_mirroring(self.primary_fs_name, self.primary_fs_id) diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_misc.py ceph-16.2.6/qa/tasks/cephfs/test_misc.py --- ceph-16.2.5/qa/tasks/cephfs/test_misc.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_misc.py 2021-09-16 14:27:19.000000000 +0000 @@ -82,7 +82,7 @@ '--yes-i-really-really-mean-it') self.fs.mon_manager.raw_cluster_cmd('osd', 'pool', 'create', self.fs.metadata_pool_name, - self.fs.pgs_per_fs_pool.__str__()) + '--pg_num_min', str(self.fs.pg_num_min)) # insert a garbage object self.fs.radosm(["put", "foo", "-"], stdin=StringIO("bar")) @@ -119,7 +119,7 @@ '--yes-i-really-really-mean-it') self.fs.mon_manager.raw_cluster_cmd('osd', 'pool', 'create', self.fs.metadata_pool_name, - self.fs.pgs_per_fs_pool.__str__()) + '--pg_num_min', str(self.fs.pg_num_min)) self.fs.mon_manager.raw_cluster_cmd('fs', 'new', self.fs.name, self.fs.metadata_pool_name, data_pool_name) diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_nfs.py ceph-16.2.6/qa/tasks/cephfs/test_nfs.py --- ceph-16.2.5/qa/tasks/cephfs/test_nfs.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_nfs.py 2021-09-16 14:27:19.000000000 +0000 @@ -264,9 +264,11 @@ return raise + self.ctx.cluster.run(args=['sudo', 'chmod', '1777', '/mnt']) + try: - self.ctx.cluster.run(args=['sudo', 'touch', '/mnt/test']) - out_mnt = self._sys_cmd(['sudo', 'ls', '/mnt']) + self.ctx.cluster.run(args=['touch', '/mnt/test']) + out_mnt = self._sys_cmd(['ls', '/mnt']) self.assertEqual(out_mnt, b'test\n') finally: self.ctx.cluster.run(args=['sudo', 'umount', '/mnt']) diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_scrub_checks.py ceph-16.2.6/qa/tasks/cephfs/test_scrub_checks.py --- ceph-16.2.5/qa/tasks/cephfs/test_scrub_checks.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_scrub_checks.py 2021-09-16 14:27:19.000000000 +0000 @@ -303,8 +303,8 @@ mds_rank = 0 test_dir = "scrub_repair_path" - self.mount_a.run_shell(["sudo", "mkdir", test_dir]) - self.mount_a.run_shell(["sudo", "touch", "{0}/file".format(test_dir)]) + self.mount_a.run_shell(["mkdir", test_dir]) + self.mount_a.run_shell(["touch", "{0}/file".format(test_dir)]) dir_objname = "{:x}.00000000".format(self.mount_a.path_to_ino(test_dir)) self.mount_a.umount_wait() @@ -323,7 +323,7 @@ # fragstat indicates the directory is not empty, rmdir should fail with self.assertRaises(CommandFailedError) as ar: - self.mount_a.run_shell(["sudo", "rmdir", test_dir]) + self.mount_a.run_shell(["rmdir", test_dir]) self.assertEqual(ar.exception.exitstatus, 1) self.tell_command(mds_rank, "scrub start /{0} repair".format(test_dir), @@ -333,7 +333,7 @@ time.sleep(10) # fragstat should be fixed - self.mount_a.run_shell(["sudo", "rmdir", test_dir]) + self.mount_a.run_shell(["rmdir", test_dir]) @staticmethod def json_validator(json_out, rc, element, expected_value): diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_sessionmap.py ceph-16.2.6/qa/tasks/cephfs/test_sessionmap.py --- ceph-16.2.5/qa/tasks/cephfs/test_sessionmap.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_sessionmap.py 2021-09-16 14:27:19.000000000 +0000 @@ -41,21 +41,26 @@ the conn count goes back to where it started (i.e. we aren't leaving connections open) """ + self.config_set('mds', 'ms_async_reap_threshold', '1') + self.mount_a.umount_wait() self.mount_b.umount_wait() status = self.fs.status() s = self._get_connection_count(status=status) self.fs.rank_tell(["session", "ls"], status=status) - e = self._get_connection_count(status=status) - - self.assertEqual(s, e) + self.wait_until_true( + lambda: self._get_connection_count(status=status) == s, + timeout=30 + ) def test_mount_conn_close(self): """ That when a client unmounts, the thread count on the MDS goes back to what it was before the client mounted """ + self.config_set('mds', 'ms_async_reap_threshold', '1') + self.mount_a.umount_wait() self.mount_b.umount_wait() @@ -64,9 +69,10 @@ self.mount_a.mount_wait() self.assertGreater(self._get_connection_count(status=status), s) self.mount_a.umount_wait() - e = self._get_connection_count(status=status) - - self.assertEqual(s, e) + self.wait_until_true( + lambda: self._get_connection_count(status=status) == s, + timeout=30 + ) def test_version_splitting(self): """ diff -Nru ceph-16.2.5/qa/tasks/cephfs/test_volumes.py ceph-16.2.6/qa/tasks/cephfs/test_volumes.py --- ceph-16.2.5/qa/tasks/cephfs/test_volumes.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/cephfs/test_volumes.py 2021-09-16 14:27:19.000000000 +0000 @@ -233,20 +233,20 @@ subvolpath = self._get_subvolume_path(self.volname, subvolume, group_name=subvolume_group) if pool is not None: - self.mount_a.setfattr(subvolpath, 'ceph.dir.layout.pool', pool) + self.mount_a.setfattr(subvolpath, 'ceph.dir.layout.pool', pool, sudo=True) if pool_namespace is not None: - self.mount_a.setfattr(subvolpath, 'ceph.dir.layout.pool_namespace', pool_namespace) + self.mount_a.setfattr(subvolpath, 'ceph.dir.layout.pool_namespace', pool_namespace, sudo=True) def _do_subvolume_attr_update(self, subvolume, uid, gid, mode, subvolume_group=None): subvolpath = self._get_subvolume_path(self.volname, subvolume, group_name=subvolume_group) # mode - self.mount_a.run_shell(['chmod', mode, subvolpath]) + self.mount_a.run_shell(['chmod', mode, subvolpath], sudo=True) # ownership - self.mount_a.run_shell(['chown', uid, subvolpath]) - self.mount_a.run_shell(['chgrp', gid, subvolpath]) + self.mount_a.run_shell(['chown', uid, subvolpath], sudo=True) + self.mount_a.run_shell(['chgrp', gid, subvolpath], sudo=True) def _do_subvolume_io(self, subvolume, subvolume_group=None, create_dir=None, number_of_files=DEFAULT_NUMBER_OF_FILES, file_size=DEFAULT_FILE_SIZE): @@ -262,7 +262,7 @@ io_path = subvolpath if create_dir: io_path = os.path.join(subvolpath, create_dir) - self.mount_a.run_shell(["mkdir", "-p", io_path]) + self.mount_a.run_shell_payload(f"mkdir -p {io_path}") log.debug("filling subvolume {0} with {1} files each {2}MB size under directory {3}".format(subvolume, number_of_files, file_size, io_path)) for i in range(number_of_files): @@ -278,11 +278,11 @@ # this symlink's ownership would be changed sym_path2 = os.path.join(dir_path, "sym.0") - self.mount_a.run_shell(["sudo", "mkdir", dir_path], omit_sudo=False) - self.mount_a.run_shell(["sudo", "ln", "-s", "./{}".format(reg_file), sym_path1], omit_sudo=False) - self.mount_a.run_shell(["sudo", "ln", "-s", "./{}".format(reg_file), sym_path2], omit_sudo=False) + self.mount_a.run_shell(["mkdir", dir_path]) + self.mount_a.run_shell(["ln", "-s", "./{}".format(reg_file), sym_path1]) + self.mount_a.run_shell(["ln", "-s", "./{}".format(reg_file), sym_path2]) # flip ownership to nobody. assumption: nobody's id is 65534 - self.mount_a.run_shell(["sudo", "chown", "-h", "65534:65534", sym_path2], omit_sudo=False) + self.mount_a.run_shell(["chown", "-h", "65534:65534", sym_path2], sudo=True, omit_sudo=False) def _wait_for_trash_empty(self, timeout=30): # XXX: construct the trash dir path (note that there is no mgr @@ -301,7 +301,7 @@ group = subvol_group if subvol_group is not None else '_nogroup' metapath = os.path.join(".", "volumes", group, subvol_name, ".meta") - out = self.mount_a.run_shell(['cat', metapath]) + out = self.mount_a.run_shell(['cat', metapath], sudo=True) lines = out.stdout.getvalue().strip().split('\n') sv_version = -1 for line in lines: @@ -316,16 +316,16 @@ basepath = os.path.join("volumes", group, subvol_name) uuid_str = str(uuid.uuid4()) createpath = os.path.join(basepath, uuid_str) - self.mount_a.run_shell(['mkdir', '-p', createpath]) + self.mount_a.run_shell(['mkdir', '-p', createpath], sudo=True) # create a v1 snapshot, to prevent auto upgrades if has_snapshot: snappath = os.path.join(createpath, ".snap", "fake") - self.mount_a.run_shell(['mkdir', '-p', snappath]) + self.mount_a.run_shell(['mkdir', '-p', snappath], sudo=True) # add required xattrs to subvolume default_pool = self.mount_a.getfattr(".", "ceph.dir.layout.pool") - self.mount_a.setfattr(createpath, 'ceph.dir.layout.pool', default_pool) + self.mount_a.setfattr(createpath, 'ceph.dir.layout.pool', default_pool, sudo=True) # create a v1 .meta file meta_contents = "[GLOBAL]\nversion = 1\ntype = {0}\npath = {1}\nstate = {2}\n".format(subvol_type, "/" + createpath, state) @@ -333,17 +333,16 @@ # add a fake clone source meta_contents = meta_contents + '[source]\nvolume = fake\nsubvolume = fake\nsnapshot = fake\n' meta_filepath1 = os.path.join(self.mount_a.mountpoint, basepath, ".meta") - self.mount_a.client_remote.write_file(meta_filepath1, - meta_contents, sudo=True) + self.mount_a.client_remote.write_file(meta_filepath1, meta_contents, sudo=True) return createpath def _update_fake_trash(self, subvol_name, subvol_group=None, trash_name='fake', create=True): group = subvol_group if subvol_group is not None else '_nogroup' trashpath = os.path.join("volumes", group, subvol_name, '.trash', trash_name) if create: - self.mount_a.run_shell(['mkdir', '-p', trashpath]) + self.mount_a.run_shell(['mkdir', '-p', trashpath], sudo=True) else: - self.mount_a.run_shell(['rmdir', trashpath]) + self.mount_a.run_shell(['rmdir', trashpath], sudo=True) def _configure_guest_auth(self, guest_mount, authid, key): """ @@ -612,7 +611,7 @@ # create group self._fs_cmd("subvolumegroup", "create", self.volname, group1) - self._fs_cmd("subvolumegroup", "create", self.volname, group2, "--mode", "777") + self._fs_cmd("subvolumegroup", "create", self.volname, group2, f"--mode={expected_mode2}") group1_path = self._get_subvolume_group_path(self.volname, group1) group2_path = self._get_subvolume_group_path(self.volname, group2) @@ -726,7 +725,7 @@ # create subvolumes for subvolume in subvolumes: - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") self._do_subvolume_io(subvolume, number_of_files=10) self.mount_a.umount_wait() @@ -1157,7 +1156,7 @@ else: raise RuntimeError("expected renaming subvolume incarnation out of subvolume directory to fail") """) - self.mount_a.run_python(rename_script.format(src=srcpath, dst=dstpath)) + self.mount_a.run_python(rename_script.format(src=srcpath, dst=dstpath), sudo=True) # remove subvolume self._fs_cmd("subvolume", "rm", self.volname, subvolume) @@ -1196,11 +1195,11 @@ # emulate a old-fashioned subvolume in a custom group createpath = os.path.join(".", "volumes", group, subvolume) - self.mount_a.run_shell(['mkdir', '-p', createpath]) + self.mount_a.run_shell(['mkdir', '-p', createpath], sudo=True) # add required xattrs to subvolume default_pool = self.mount_a.getfattr(".", "ceph.dir.layout.pool") - self.mount_a.setfattr(createpath, 'ceph.dir.layout.pool', default_pool) + self.mount_a.setfattr(createpath, 'ceph.dir.layout.pool', default_pool, sudo=True) mount_path = os.path.join("/", "volumes", group, subvolume) @@ -1216,7 +1215,7 @@ self._configure_guest_auth(guest_mount, authid, key) # mount the subvolume, and write to it - guest_mount.mount(cephfs_mntpt=mount_path) + guest_mount.mount_wait(cephfs_mntpt=mount_path) guest_mount.write_n_mb("data.bin", 1) # authorize guest authID read access to subvolume @@ -1226,7 +1225,7 @@ # guest client sees the change in access level to read only after a # remount of the subvolume. guest_mount.umount_wait() - guest_mount.mount(cephfs_mntpt=mount_path) + guest_mount.mount_wait(cephfs_mntpt=mount_path) # read existing content of the subvolume self.assertListEqual(guest_mount.ls(guest_mount.mountpoint), ["data.bin"]) @@ -1253,7 +1252,7 @@ guest_mount.umount_wait() # create group - self._fs_cmd("subvolumegroup", "create", self.volname, group) + self._fs_cmd("subvolumegroup", "create", self.volname, group, "--mode=777") # create subvolume in group self._fs_cmd("subvolume", "create", self.volname, subvolume, "--group_name", group) @@ -1272,7 +1271,7 @@ self._configure_guest_auth(guest_mount, authid, key) # mount the subvolume, and write to it - guest_mount.mount(cephfs_mntpt=mount_path) + guest_mount.mount_wait(cephfs_mntpt=mount_path) guest_mount.write_n_mb("data.bin", 1) # authorize guest authID read access to subvolume @@ -1282,7 +1281,7 @@ # guest client sees the change in access level to read only after a # remount of the subvolume. guest_mount.umount_wait() - guest_mount.mount(cephfs_mntpt=mount_path) + guest_mount.mount_wait(cephfs_mntpt=mount_path) # read existing content of the subvolume self.assertListEqual(guest_mount.ls(guest_mount.mountpoint), ["data.bin"]) @@ -1630,7 +1629,7 @@ # Induce partial auth update state by modifying the auth metadata file, # and then run authorize again. - guest_mount.run_shell(['sed', '-i', 's/false/true/g', 'volumes/{0}'.format(auth_metadata_filename)]) + guest_mount.run_shell(['sed', '-i', 's/false/true/g', 'volumes/{0}'.format(auth_metadata_filename)], sudo=True) # Authorize 'guestclient_1' to access the subvolume. self._fs_cmd("subvolume", "authorize", self.volname, subvolume, guestclient_1["auth_id"], @@ -1686,7 +1685,7 @@ # Induce partial auth update state by modifying the auth metadata file, # and then run de-authorize. - guest_mount.run_shell(['sed', '-i', 's/false/true/g', 'volumes/{0}'.format(auth_metadata_filename)]) + guest_mount.run_shell(['sed', '-i', 's/false/true/g', 'volumes/{0}'.format(auth_metadata_filename)], sudo=True) # Deauthorize 'guestclient_1' to access the subvolume2. self._fs_cmd("subvolume", "deauthorize", self.volname, subvolume2, guestclient_1["auth_id"], @@ -1739,7 +1738,7 @@ self.assertIn(auth_metadata_filename, guest_mount.ls("volumes")) # Replace 'subvolumes' to 'volumes', old style auth-metadata file - guest_mount.run_shell(['sed', '-i', 's/subvolumes/volumes/g', 'volumes/{0}'.format(auth_metadata_filename)]) + guest_mount.run_shell(['sed', '-i', 's/subvolumes/volumes/g', 'volumes/{0}'.format(auth_metadata_filename)], sudo=True) # Authorize 'guestclient_1' to access the subvolume2. This should transparently update 'volumes' to 'subvolumes' self._fs_cmd("subvolume", "authorize", self.volname, subvolume2, guestclient_1["auth_id"], @@ -1817,7 +1816,7 @@ self.assertIn(auth_metadata_filename, guest_mount.ls("volumes")) # Replace 'subvolumes' to 'volumes', old style auth-metadata file - guest_mount.run_shell(['sed', '-i', 's/subvolumes/volumes/g', 'volumes/{0}'.format(auth_metadata_filename)]) + guest_mount.run_shell(['sed', '-i', 's/subvolumes/volumes/g', 'volumes/{0}'.format(auth_metadata_filename)], sudo=True) # Deauthorize 'guestclient_1' to access the subvolume2. This should update 'volumes' to subvolumes' self._fs_cmd("subvolume", "deauthorize", self.volname, subvolume2, auth_id, "--group_name", group) @@ -1875,7 +1874,7 @@ # subvolumes. Mount the two subvolumes. Write data to the volumes. for i in range(2): # Create subvolume. - self._fs_cmd("subvolume", "create", self.volname, subvolumes[i], "--group_name", group) + self._fs_cmd("subvolume", "create", self.volname, subvolumes[i], "--group_name", group, "--mode=777") # authorize guest authID read-write access to subvolume key = self._fs_cmd("subvolume", "authorize", self.volname, subvolumes[i], guestclient_1["auth_id"], @@ -1887,7 +1886,7 @@ self._configure_guest_auth(guest_mounts[i], auth_id, key) # mount the subvolume, and write to it - guest_mounts[i].mount(cephfs_mntpt=mount_path) + guest_mounts[i].mount_wait(cephfs_mntpt=mount_path) guest_mounts[i].write_n_mb("data.bin", 1) # Evict client, guest_mounts[0], using auth ID 'guest' and has mounted @@ -2010,7 +2009,7 @@ osize = self.DEFAULT_FILE_SIZE*1024*1024*20 # create subvolume subvolname = self._generate_random_subvolume_name() - self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", str(osize)) + self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", str(osize), "--mode=777") # make sure it exists subvolpath = self._get_subvolume_path(self.volname, subvolname) @@ -2057,7 +2056,7 @@ osize = self.DEFAULT_FILE_SIZE*1024*1024*20 # create subvolume subvolname = self._generate_random_subvolume_name() - self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", str(osize)) + self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", str(osize), "--mode=777") # make sure it exists subvolpath = self._get_subvolume_path(self.volname, subvolname) @@ -2105,7 +2104,7 @@ osize = self.DEFAULT_FILE_SIZE*1024*1024*10 # create subvolume of quota 10MB and make sure it exists subvolname = self._generate_random_subvolume_name() - self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", str(osize)) + self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", str(osize), "--mode=777") subvolpath = self._get_subvolume_path(self.volname, subvolname) self.assertNotEqual(subvolpath, None) @@ -2181,7 +2180,7 @@ # create subvolume subvolname = self._generate_random_subvolume_name() self._fs_cmd("subvolume", "create", self.volname, subvolname, "--size", - str(self.DEFAULT_FILE_SIZE*1024*1024*5)) + str(self.DEFAULT_FILE_SIZE*1024*1024*5), "--mode=777") # make sure it exists subvolpath = self._get_subvolume_path(self.volname, subvolname) @@ -2482,7 +2481,7 @@ snapshot, snap_missing = self._generate_random_snapshot_name(2) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=1) @@ -2594,13 +2593,13 @@ # Create snapshot at ancestral level ancestral_snappath1 = os.path.join(".", "volumes", group, ".snap", "ancestral_snap_1") ancestral_snappath2 = os.path.join(".", "volumes", group, ".snap", "ancestral_snap_2") - self.mount_a.run_shell(['mkdir', '-p', ancestral_snappath1, ancestral_snappath2]) + self.mount_a.run_shell(['mkdir', '-p', ancestral_snappath1, ancestral_snappath2], sudo=True) subvolsnapshotls = json.loads(self._fs_cmd('subvolume', 'snapshot', 'ls', self.volname, subvolume, group)) self.assertEqual(len(subvolsnapshotls), snap_count) # remove ancestral snapshots - self.mount_a.run_shell(['rmdir', ancestral_snappath1, ancestral_snappath2]) + self.mount_a.run_shell(['rmdir', ancestral_snappath1, ancestral_snappath2], sudo=True) # remove snapshot for snapshot in snapshots: @@ -2634,7 +2633,7 @@ # Create snapshot at ancestral level ancestral_snap_name = "ancestral_snap_1" ancestral_snappath1 = os.path.join(".", "volumes", group, ".snap", ancestral_snap_name) - self.mount_a.run_shell(['mkdir', '-p', ancestral_snappath1]) + self.mount_a.run_shell(['mkdir', '-p', ancestral_snappath1], sudo=True) # Validate existence of inherited snapshot group_path = os.path.join(".", "volumes", group) @@ -2652,7 +2651,7 @@ self.fail("expected snapshot info of inherited snapshot to fail") # remove ancestral snapshots - self.mount_a.run_shell(['rmdir', ancestral_snappath1]) + self.mount_a.run_shell(['rmdir', ancestral_snappath1], sudo=True) # remove subvolume self._fs_cmd("subvolume", "rm", self.volname, subvolume, "--group_name", group) @@ -2682,7 +2681,7 @@ # Create snapshot at ancestral level ancestral_snap_name = "ancestral_snap_1" ancestral_snappath1 = os.path.join(".", "volumes", group, ".snap", ancestral_snap_name) - self.mount_a.run_shell(['mkdir', '-p', ancestral_snappath1]) + self.mount_a.run_shell(['mkdir', '-p', ancestral_snappath1], sudo=True) # Validate existence of inherited snap group_path = os.path.join(".", "volumes", group) @@ -2700,7 +2699,7 @@ self.fail("expected removing inheirted snapshot to fail") # remove ancestral snapshots - self.mount_a.run_shell(['rmdir', ancestral_snappath1]) + self.mount_a.run_shell(['rmdir', ancestral_snappath1], sudo=True) # remove subvolume self._fs_cmd("subvolume", "rm", self.volname, subvolume, group) @@ -2730,7 +2729,7 @@ # Create subvolumegroup snapshot group_snapshot_path = os.path.join(".", "volumes", group, ".snap", group_snapshot) - self.mount_a.run_shell(['mkdir', '-p', group_snapshot_path]) + self.mount_a.run_shell(['mkdir', '-p', group_snapshot_path], sudo=True) # Validate existence of subvolumegroup snapshot self.mount_a.run_shell(['ls', group_snapshot_path]) @@ -2744,7 +2743,7 @@ self.fail("expected subvolume snapshot creation with same name as subvolumegroup snapshot to fail") # remove subvolumegroup snapshot - self.mount_a.run_shell(['rmdir', group_snapshot_path]) + self.mount_a.run_shell(['rmdir', group_snapshot_path], sudo=True) # remove subvolume self._fs_cmd("subvolume", "rm", self.volname, subvolume, group) @@ -3057,7 +3056,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=64) @@ -3115,7 +3114,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=1) @@ -3175,7 +3174,7 @@ osize = self.DEFAULT_FILE_SIZE*1024*1024*12 # create subvolume, in an isolated namespace with a specified size - self._fs_cmd("subvolume", "create", self.volname, subvolume, "--namespace-isolated", "--size", str(osize)) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--namespace-isolated", "--size", str(osize), "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=8) @@ -3218,7 +3217,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=64) @@ -3226,6 +3225,9 @@ # snapshot subvolume self._fs_cmd("subvolume", "snapshot", "create", self.volname, subvolume, snapshot) + # Insert delay at the beginning of snapshot clone + self.config_set('mgr', 'mgr/volumes/snapshot_clone_delay', 2) + # schedule a clone self._fs_cmd("subvolume", "snapshot", "clone", self.volname, subvolume, snapshot, clone) @@ -3264,7 +3266,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=64) @@ -3272,6 +3274,9 @@ # snapshot subvolume self._fs_cmd("subvolume", "snapshot", "create", self.volname, subvolume, snapshot) + # Insert delay at the beginning of snapshot clone + self.config_set('mgr', 'mgr/volumes/snapshot_clone_delay', 2) + # schedule a clone self._fs_cmd("subvolume", "snapshot", "clone", self.volname, subvolume, snapshot, clone) @@ -3309,7 +3314,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=64) @@ -3317,6 +3322,9 @@ # snapshot subvolume self._fs_cmd("subvolume", "snapshot", "create", self.volname, subvolume, snapshot) + # Insert delay at the beginning of snapshot clone + self.config_set('mgr', 'mgr/volumes/snapshot_clone_delay', 2) + # schedule a clone self._fs_cmd("subvolume", "snapshot", "clone", self.volname, subvolume, snapshot, clone) @@ -3357,7 +3365,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # store path for clone verification subvol1_path = self._get_subvolume_path(self.volname, subvolume) @@ -3431,7 +3439,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # store path for clone verification subvol_path = self._get_subvolume_path(self.volname, subvolume) @@ -3476,7 +3484,7 @@ clone = self._generate_random_clone_name(1) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=16) @@ -3488,7 +3496,7 @@ self._fs_cmd("subvolume", "rm", self.volname, subvolume, "--retain-snapshots") # recreate subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # get and store path for clone verification subvol2_path = self._get_subvolume_path(self.volname, subvolume) @@ -3533,7 +3541,7 @@ snapshot = self._generate_random_snapshot_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # store path for clone verification subvol_path = self._get_subvolume_path(self.volname, subvolume) @@ -3632,7 +3640,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io_mixed(subvolume) @@ -3665,7 +3673,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=64) @@ -3698,7 +3706,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # Create a file with suid, guid bits set along with executable bit. args = ["subvolume", "getpath", self.volname, subvolume] @@ -3740,7 +3748,7 @@ clone1, clone2 = self._generate_random_clone_name(2) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=32) @@ -3793,7 +3801,7 @@ clone = self._generate_random_clone_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=128) @@ -3801,6 +3809,9 @@ # snapshot subvolume self._fs_cmd("subvolume", "snapshot", "create", self.volname, subvolume, snapshot) + # Insert delay at the beginning of snapshot clone + self.config_set('mgr', 'mgr/volumes/snapshot_clone_delay', 2) + # schedule a clone self._fs_cmd("subvolume", "snapshot", "clone", self.volname, subvolume, snapshot, clone) @@ -3841,7 +3852,7 @@ clones = self._generate_random_clone_name(NR_CLONES) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=4, file_size=FILE_SIZE_MB) @@ -3898,7 +3909,7 @@ self._fs_cmd("subvolumegroup", "create", self.volname, c_group) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume, s_group) + self._fs_cmd("subvolume", "create", self.volname, subvolume, s_group, "--mode=777") # do some IO self._do_subvolume_io(subvolume, subvolume_group=s_group, number_of_files=32) @@ -3940,7 +3951,7 @@ nr_files = int((pool_capacity * 0.99) / (TestVolumes.DEFAULT_FILE_SIZE * 1024 * 1024)) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=nr_files) @@ -3999,8 +4010,8 @@ clone = self._generate_random_clone_name() # create subvolumes - self._fs_cmd("subvolume", "create", self.volname, subvolume1) - self._fs_cmd("subvolume", "create", self.volname, subvolume2) + self._fs_cmd("subvolume", "create", self.volname, subvolume1, "--mode=777") + self._fs_cmd("subvolume", "create", self.volname, subvolume2, "--mode=777") # do some IO self._do_subvolume_io(subvolume1, number_of_files=32) @@ -4055,7 +4066,7 @@ newid = self.fs.add_data_pool(new_pool) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=32) @@ -4096,7 +4107,7 @@ group = self._generate_random_group_name() # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume) + self._fs_cmd("subvolume", "create", self.volname, subvolume, "--mode=777") # do some IO self._do_subvolume_io(subvolume, number_of_files=32) @@ -4185,11 +4196,11 @@ # emulate a old-fashioned subvolume createpath = os.path.join(".", "volumes", "_nogroup", subvolume) - self.mount_a.run_shell(['mkdir', '-p', createpath]) + self.mount_a.run_shell_payload(f"mkdir -p -m 777 {createpath}", sudo=True) # add required xattrs to subvolume default_pool = self.mount_a.getfattr(".", "ceph.dir.layout.pool") - self.mount_a.setfattr(createpath, 'ceph.dir.layout.pool', default_pool) + self.mount_a.setfattr(createpath, 'ceph.dir.layout.pool', default_pool, sudo=True) # do some IO self._do_subvolume_io(subvolume, number_of_files=64) @@ -4200,6 +4211,9 @@ # ensure metadata file is in legacy location, with required version v1 self._assert_meta_location_and_version(self.volname, subvolume, version=1, legacy=True) + # Insert delay at the beginning of snapshot clone + self.config_set('mgr', 'mgr/volumes/snapshot_clone_delay', 2) + # schedule a clone self._fs_cmd("subvolume", "snapshot", "clone", self.volname, subvolume, snapshot, clone) @@ -4249,6 +4263,25 @@ max_concurrent_clones = int(self.config_get('mgr', 'mgr/volumes/max_concurrent_clones')) self.assertEqual(max_concurrent_clones, 2) + def test_subvolume_snapshot_config_snapshot_clone_delay(self): + """ + Validate 'snapshot_clone_delay' config option + """ + + # get the default delay before starting the clone + default_timeout = int(self.config_get('mgr', 'mgr/volumes/snapshot_clone_delay')) + self.assertEqual(default_timeout, 0) + + # Insert delay of 2 seconds at the beginning of the snapshot clone + self.config_set('mgr', 'mgr/volumes/snapshot_clone_delay', 2) + default_timeout = int(self.config_get('mgr', 'mgr/volumes/snapshot_clone_delay')) + self.assertEqual(default_timeout, 2) + + # Decrease number of cloner threads + self.config_set('mgr', 'mgr/volumes/max_concurrent_clones', 2) + max_concurrent_clones = int(self.config_get('mgr', 'mgr/volumes/max_concurrent_clones')) + self.assertEqual(max_concurrent_clones, 2) + def test_subvolume_under_group_snapshot_clone(self): subvolume = self._generate_random_subvolume_name() group = self._generate_random_group_name() @@ -4259,7 +4292,7 @@ self._fs_cmd("subvolumegroup", "create", self.volname, group) # create subvolume - self._fs_cmd("subvolume", "create", self.volname, subvolume, group) + self._fs_cmd("subvolume", "create", self.volname, subvolume, group, "--mode=777") # do some IO self._do_subvolume_io(subvolume, subvolume_group=group, number_of_files=32) @@ -4426,11 +4459,11 @@ # emulate a old-fashioned subvolume -- one in the default group and # the other in a custom group createpath1 = os.path.join(".", "volumes", "_nogroup", subvolume1) - self.mount_a.run_shell(['mkdir', '-p', createpath1]) + self.mount_a.run_shell(['mkdir', '-p', createpath1], sudo=True) # create group createpath2 = os.path.join(".", "volumes", group, subvolume2) - self.mount_a.run_shell(['mkdir', '-p', createpath2]) + self.mount_a.run_shell(['mkdir', '-p', createpath2], sudo=True) # this would auto-upgrade on access without anyone noticing subvolpath1 = self._fs_cmd("subvolume", "getpath", self.volname, subvolume1) diff -Nru ceph-16.2.5/qa/tasks/ceph_manager.py ceph-16.2.6/qa/tasks/ceph_manager.py --- ceph-16.2.5/qa/tasks/ceph_manager.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/ceph_manager.py 2021-09-16 14:27:19.000000000 +0000 @@ -3,6 +3,7 @@ """ from functools import wraps import contextlib +import errno import random import signal import time @@ -3078,13 +3079,22 @@ Loop until quorum size is reached. """ self.log('waiting for quorum size %d' % size) - start = time.time() - while not len(self.get_mon_quorum()) == size: - if timeout is not None: - assert time.time() - start < timeout, \ - ('failed to reach quorum size %d ' - 'before timeout expired' % size) - time.sleep(3) + sleep = 3 + with safe_while(sleep=sleep, + tries=timeout // sleep, + action=f'wait for quorum size {size}') as proceed: + while proceed(): + try: + if len(self.get_mon_quorum()) == size: + break + except CommandFailedError as e: + # could fail instea4d of blocked if the rotating key of the + # connected monitor is not updated yet after they form the + # quorum + if e.exitstatus == errno.EACCES: + pass + else: + raise self.log("quorum is size %d" % size) def get_mon_health(self, debug=False): diff -Nru ceph-16.2.5/qa/tasks/mds_pre_upgrade.py ceph-16.2.6/qa/tasks/mds_pre_upgrade.py --- ceph-16.2.5/qa/tasks/mds_pre_upgrade.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/mds_pre_upgrade.py 2021-09-16 14:27:19.000000000 +0000 @@ -3,7 +3,6 @@ """ import logging -import time from tasks.cephfs.filesystem import Filesystem @@ -22,22 +21,7 @@ 'snap-upgrade task only accepts a dict for configuration' fs = Filesystem(ctx) - status = fs.getinfo() - + fs.getinfo() # load name + fs.set_allow_standby_replay(False) fs.set_max_mds(1) fs.reach_max_mds() - - # Stop standbys now to minimize time rank 0 is down in subsequent: - # tasks: - # - ceph.stop: [mds.*] - rank0 = fs.get_rank(rank=0, status=status) - for daemon in ctx.daemons.iter_daemons_of_role('mds', fs.mon_manager.cluster): - if rank0['name'] != daemon.id_: - daemon.stop() - - for i in range(1, 10): - time.sleep(5) # time for FSMap to update - status = fs.getinfo() - if len(list(status.get_standbys())) == 0: - break - assert(len(list(status.get_standbys())) == 0) diff -Nru ceph-16.2.5/qa/tasks/mgr/dashboard/test_motd.py ceph-16.2.6/qa/tasks/mgr/dashboard/test_motd.py --- ceph-16.2.5/qa/tasks/mgr/dashboard/test_motd.py 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/qa/tasks/mgr/dashboard/test_motd.py 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# pylint: disable=too-many-public-methods + +from __future__ import absolute_import + +import time + +from .helper import DashboardTestCase + + +class MotdTest(DashboardTestCase): + @classmethod + def tearDownClass(cls): + cls._ceph_cmd(['dashboard', 'motd', 'clear']) + super(MotdTest, cls).tearDownClass() + + def setUp(self): + super(MotdTest, self).setUp() + self._ceph_cmd(['dashboard', 'motd', 'clear']) + + def test_none(self): + data = self._get('/ui-api/motd') + self.assertStatus(200) + self.assertIsNone(data) + + def test_set(self): + self._ceph_cmd(['dashboard', 'motd', 'set', 'info', '0', 'foo bar baz']) + data = self._get('/ui-api/motd') + self.assertStatus(200) + self.assertIsInstance(data, dict) + + def test_expired(self): + self._ceph_cmd(['dashboard', 'motd', 'set', 'info', '2s', 'foo bar baz']) + time.sleep(5) + data = self._get('/ui-api/motd') + self.assertStatus(200) + self.assertIsNone(data) diff -Nru ceph-16.2.5/qa/tasks/mgr/dashboard/test_rgw.py ceph-16.2.6/qa/tasks/mgr/dashboard/test_rgw.py --- ceph-16.2.5/qa/tasks/mgr/dashboard/test_rgw.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/mgr/dashboard/test_rgw.py 2021-09-16 14:27:19.000000000 +0000 @@ -70,29 +70,20 @@ AUTH_ROLES = ['rgw-manager'] - def setUp(self): - super(RgwApiCredentialsTest, self).setUp() - # Restart the Dashboard module to ensure that the connection to the - # RGW Admin Ops API is re-established with the new credentials. - self.logout() - self._ceph_cmd(['mgr', 'module', 'disable', 'dashboard']) - self._ceph_cmd(['mgr', 'module', 'enable', 'dashboard', '--force']) - # Set the default credentials. - self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-secret-key'], 'admin') - self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-access-key'], 'admin') - super(RgwApiCredentialsTest, self).setUp() - - def test_no_access_secret_key(self): - self._ceph_cmd(['dashboard', 'reset-rgw-api-secret-key']) - self._ceph_cmd(['dashboard', 'reset-rgw-api-access-key']) + def test_invalid_credentials(self): + self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-secret-key'], 'invalid') + self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-access-key'], 'invalid') resp = self._get('/api/rgw/user') - self.assertStatus(500) + self.assertStatus(404) self.assertIn('detail', resp) self.assertIn('component', resp) - self.assertIn('No RGW credentials found', resp['detail']) + self.assertIn('Error connecting to Object Gateway', resp['detail']) self.assertEqual(resp['component'], 'rgw') def test_success(self): + # Set the default credentials. + self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-secret-key'], 'admin') + self._ceph_cmd_with_secret(['dashboard', 'set-rgw-api-access-key'], 'admin') data = self._get('/api/rgw/status') self.assertStatus(200) self.assertIn('available', data) @@ -211,6 +202,11 @@ 'tenant': JLeaf(str), }, allow_unknown=True)) + # List all buckets names without stats. + data = self._get('/api/rgw/bucket?stats=false') + self.assertStatus(200) + self.assertEqual(data, ['teuth-test-bucket']) + # Get the bucket. data = self._get('/api/rgw/bucket/teuth-test-bucket') self.assertStatus(200) diff -Nru ceph-16.2.5/qa/tasks/mgr/dashboard/test_settings.py ceph-16.2.6/qa/tasks/mgr/dashboard/test_settings.py --- ceph-16.2.5/qa/tasks/mgr/dashboard/test_settings.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/mgr/dashboard/test_settings.py 2021-09-16 14:27:19.000000000 +0000 @@ -51,15 +51,15 @@ def test_bulk_set(self): self._put('/api/settings', { - 'RGW_API_HOST': 'somehost', - 'RGW_API_PORT': 7777, + 'RGW_API_ACCESS_KEY': 'dummy-key', + 'RGW_API_SECRET_KEY': 'dummy-secret', }) self.assertStatus(200) - host = self._get('/api/settings/rgw-api-host')['value'] + access_key = self._get('/api/settings/rgw-api-access-key')['value'] self.assertStatus(200) - self.assertEqual('somehost', host) + self.assertEqual('dummy-key', access_key) - port = self._get('/api/settings/rgw-api-port')['value'] + secret_key = self._get('/api/settings/rgw-api-secret-key')['value'] self.assertStatus(200) - self.assertEqual(7777, port) + self.assertEqual('dummy-secret', secret_key) diff -Nru ceph-16.2.5/qa/tasks/mgr/test_insights.py ceph-16.2.6/qa/tasks/mgr/test_insights.py --- ceph-16.2.5/qa/tasks/mgr/test_insights.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/mgr/test_insights.py 2021-09-16 14:27:19.000000000 +0000 @@ -149,17 +149,6 @@ active_id = self.mgr_cluster.get_active_id() self.mgr_cluster.mgr_restart(active_id) - # ensure that at least one of the checks is present after the restart. - # we don't for them all to be present because "earlier" checks may not - # have sat in memory long enough to be flushed. - all_missing = True - report = self._insights() - for check in check_names: - if check in report["health"]["history"]["checks"]: - all_missing = False - break - self.assertFalse(all_missing) - # pruning really removes history self.mgr_cluster.mon_manager.raw_cluster_cmd_result( "insights", "prune-health", "0") diff -Nru ceph-16.2.5/qa/tasks/rgw_multi/tests_ps.py ceph-16.2.6/qa/tasks/rgw_multi/tests_ps.py --- ceph-16.2.5/qa/tasks/rgw_multi/tests_ps.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/tasks/rgw_multi/tests_ps.py 2021-09-16 14:27:19.000000000 +0000 @@ -3936,40 +3936,49 @@ response, status = s3_notification_conf.set_config() assert_equal(status/100, 2) + expected_keys = [] # create objects in the bucket key_name = 'foo' key = bucket.new_key(key_name) key.set_metadata(meta_key, meta_value) key.set_contents_from_string('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') + expected_keys.append(key_name) # create objects in the bucket using COPY - bucket.copy_key('copy_of_foo', bucket.name, key.name) + key_name = 'copy_of_foo' + bucket.copy_key(key_name, bucket.name, key.name) + expected_keys.append(key_name) + + # create another objects in the bucket using COPY + # but override the metadata value + key_name = 'another_copy_of_foo' + bucket.copy_key(key_name, bucket.name, key.name, metadata={meta_key: 'kaboom'}) # create objects in the bucket using multi-part upload fp = tempfile.NamedTemporaryFile(mode='w+b') - object_size = 1024 + chunk_size = 1024*1024*5 # 5MB + object_size = 10*chunk_size content = bytearray(os.urandom(object_size)) fp.write(content) fp.flush() fp.seek(0) - uploader = bucket.initiate_multipart_upload('multipart_foo', - metadata={meta_key: meta_value}) - uploader.upload_part_from_file(fp, 1) + key_name = 'multipart_foo' + uploader = bucket.initiate_multipart_upload(key_name, + metadata={meta_key: meta_value}) + for i in range(1,5): + uploader.upload_part_from_file(fp, i, size=chunk_size) + fp.seek(i*chunk_size) uploader.complete_upload() fp.close() + expected_keys.append(key_name) print('wait for 5sec for the messages...') time.sleep(5) # check amqp receiver - event_count = 0 - for event in receiver.get_and_reset_events(): - s3_event = event['Records'][0]['s3'] - assert_equal(s3_event['object']['metadata'][0]['key'], meta_prefix+meta_key) - assert_equal(s3_event['object']['metadata'][0]['val'], meta_value) - event_count +=1 - - # only PUT and POST has the metadata value - assert_equal(event_count, 2) + events = receiver.get_and_reset_events() + assert_equal(len(events), 4) # PUT, COPY, Multipart start, Multipart End + for event in events: + assert(event['Records'][0]['s3']['object']['key'] in expected_keys) # delete objects for key in bucket.list(): @@ -3977,12 +3986,7 @@ print('wait for 5sec for the messages...') time.sleep(5) # check amqp receiver - event_count = 0 - for event in receiver.get_and_reset_events(): - s3_event = event['Records'][0]['s3'] - assert_equal(s3_event['object']['metadata'][0]['key'], meta_prefix+meta_key) - assert_equal(s3_event['object']['metadata'][0]['val'], meta_value) - event_count +=1 + #assert_equal(len(receiver.get_and_reset_events()), len(expected_keys)) # all 3 object has metadata when deleted assert_equal(event_count, 3) diff -Nru ceph-16.2.5/qa/workunits/cephadm/test_cephadm.sh ceph-16.2.6/qa/workunits/cephadm/test_cephadm.sh --- ceph-16.2.5/qa/workunits/cephadm/test_cephadm.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/cephadm/test_cephadm.sh 2021-09-16 14:27:19.000000000 +0000 @@ -161,6 +161,9 @@ $CEPHADM shell --fsid $FSID -- ceph -v | grep 'ceph version' $CEPHADM shell --fsid $FSID -e FOO=BAR -- printenv | grep FOO=BAR +# test stdin +echo foo | $CEPHADM shell -- cat | grep -q foo + ## bootstrap ORIG_CONFIG=`mktemp -p $TMPDIR` CONFIG=`mktemp -p $TMPDIR` diff -Nru ceph-16.2.5/qa/workunits/mon/pg_autoscaler.sh ceph-16.2.6/qa/workunits/mon/pg_autoscaler.sh --- ceph-16.2.5/qa/workunits/mon/pg_autoscaler.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/mon/pg_autoscaler.sh 2021-09-16 14:27:19.000000000 +0000 @@ -30,6 +30,8 @@ return 0 } +function power2() { echo "x=l($1)/l(2); scale=0; 2^((x+0.5)/1)" | bc -l;} + # enable ceph config set mgr mgr/pg_autoscaler/sleep_interval 5 ceph mgr module enable pg_autoscaler @@ -40,8 +42,20 @@ ceph osd pool set a pg_autoscale_mode on ceph osd pool set b pg_autoscale_mode on -wait_for 120 "ceph osd pool get a pg_num | grep 4" -wait_for 120 "ceph osd pool get b pg_num | grep 2" +# get num pools again since we created more pools +NUM_POOLS=$(ceph osd pool ls | wc -l) + +# get pool size +POOL_SIZE_A=$(ceph osd pool get a size| grep -Eo '[0-9]{1,4}') +POOL_SIZE_B=$(ceph osd pool get b size| grep -Eo '[0-9]{1,4}') + +# calculate target pg of each pools +TARGET_PG_A=$(power2 $((($NUM_OSDS * 100)/($NUM_POOLS)/($POOL_SIZE_A)))) +TARGET_PG_B=$(power2 $((($NUM_OSDS * 100)/($NUM_POOLS)/($POOL_SIZE_B)))) + +# evaluate target_pg against pg num of each pools +wait_for 120 "ceph osd pool get a pg_num | grep $TARGET_PG_A" +wait_for 120 "ceph osd pool get b pg_num | grep $TARGET_PG_B" # target ratio ceph osd pool set a target_size_ratio 5 diff -Nru ceph-16.2.5/qa/workunits/mon/test_mon_config_key.py ceph-16.2.6/qa/workunits/mon/test_mon_config_key.py --- ceph-16.2.5/qa/workunits/mon/test_mon_config_key.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/mon/test_mon_config_key.py 2021-09-16 14:27:19.000000000 +0000 @@ -78,38 +78,18 @@ cmdlog = LOG.getChild('run_cmd') cmdlog.debug('{fc}'.format(fc=' '.join(full_cmd))) - proc = subprocess.Popen(full_cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - stdout = [] - stderr = [] - while True: - try: - out, err = proc.communicate() - if out is not None: - stdout += out.decode().split('\n') - cmdlog.debug('stdout: {s}'.format(s=out)) - if err is not None: - stdout += err.decode().split('\n') - cmdlog.debug('stderr: {s}'.format(s=err)) - except ValueError: - ret = proc.wait() - break - - if ret != expects: - cmdlog.error('cmd > {cmd}'.format(cmd=full_cmd)) - cmdlog.error("expected return '{expected}' got '{got}'".format( - expected=expects, got=ret)) + proc = subprocess.run(full_cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + if proc.returncode != expects: + cmdlog.error(f'cmd > {proc.args}') + cmdlog.error(f'expected return "{expects}" got "{proc.returncode}"') cmdlog.error('stdout') - for i in stdout: - cmdlog.error('{x}'.format(x=i)) + cmdlog.error(proc.stdout) cmdlog.error('stderr') - for i in stderr: - cmdlog.error('{x}'.format(x=i)) - + cmdlog.error(proc.stderr) -# end run_cmd def gen_data(size, rnd): chars = string.ascii_letters + string.digits diff -Nru ceph-16.2.5/qa/workunits/rados/test_envlibrados_for_rocksdb.sh ceph-16.2.6/qa/workunits/rados/test_envlibrados_for_rocksdb.sh --- ceph-16.2.5/qa/workunits/rados/test_envlibrados_for_rocksdb.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/rados/test_envlibrados_for_rocksdb.sh 2021-09-16 14:27:19.000000000 +0000 @@ -33,7 +33,7 @@ sudo subscription-manager repos --enable "codeready-builder-for-rhel-8-x86_64-rpms" ;; esac - install git gcc-c++.x86_64 snappy-devel zlib zlib-devel bzip2 bzip2-devel libradospp-devel.x86_64 cmake + install git gcc-c++.x86_64 snappy-devel zlib zlib-devel bzip2 bzip2-devel libradospp-devel.x86_64 cmake libarchive-3.3.3 ;; opensuse*|suse|sles) install git gcc-c++ snappy-devel zlib-devel libbz2-devel libradospp-devel diff -Nru ceph-16.2.5/qa/workunits/rbd/qemu-iotests.sh ceph-16.2.6/qa/workunits/rbd/qemu-iotests.sh --- ceph-16.2.5/qa/workunits/rbd/qemu-iotests.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/rbd/qemu-iotests.sh 2021-09-16 14:27:19.000000000 +0000 @@ -9,10 +9,12 @@ git clone https://github.com/qemu/qemu.git cd qemu -if lsb_release -da 2>&1 | grep -iqE '(bionic|focal)'; then + + +if grep -iqE '(bionic|focal)' /etc/os-release; then # Bionic requires a matching test harness git checkout v2.11.0 -elif lsb_release -da 2>&1 | grep -iqE '(xenial|linux release 8)'; then +elif grep -iqE '(xenial|platform:el8)' /etc/os-release; then # Xenial requires a recent test harness git checkout v2.3.0 else diff -Nru ceph-16.2.5/qa/workunits/rbd/rbd-nbd.sh ceph-16.2.6/qa/workunits/rbd/rbd-nbd.sh --- ceph-16.2.5/qa/workunits/rbd/rbd-nbd.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/rbd/rbd-nbd.sh 2021-09-16 14:27:19.000000000 +0000 @@ -4,6 +4,7 @@ . $(dirname $0)/../../standalone/ceph-helpers.sh POOL=rbd +ANOTHER_POOL=new_default_pool$$ NS=ns IMAGE=testrbdnbd$$ SIZE=64 @@ -56,6 +57,10 @@ rbd --dest-pool ${POOL} --dest-namespace "${ns}" --no-progress import \ ${DATA} ${IMAGE} done + + # create another pool + ceph osd pool create ${ANOTHER_POOL} 8 + rbd pool init ${ANOTHER_POOL} } function cleanup() @@ -69,7 +74,7 @@ rm -Rf ${TEMPDIR} if [ -n "${DEV}" ] then - _sudo rbd-nbd unmap ${DEV} + _sudo rbd device --device-type nbd unmap ${DEV} fi for ns in '' ${NS}; do @@ -84,6 +89,10 @@ fi done rbd namespace remove ${POOL}/${NS} + + # cleanup/reset default pool + rbd config global rm global rbd_default_pool + ceph osd pool delete ${ANOTHER_POOL} ${ANOTHER_POOL} --yes-i-really-really-mean-it } function expect_false() @@ -93,10 +102,11 @@ function get_pid() { - local ns=$1 + local pool=$1 + local ns=$2 - PID=$(rbd-nbd --format xml list-mapped | $XMLSTARLET sel -t -v \ - "//devices/device[pool='${POOL}'][namespace='${ns}'][image='${IMAGE}'][device='${DEV}']/id") + PID=$(rbd device --device-type nbd --format xml list | $XMLSTARLET sel -t -v \ + "//devices/device[pool='${pool}'][namespace='${ns}'][image='${IMAGE}'][device='${DEV}']/id") test -n "${PID}" || return 1 ps -p ${PID} -C rbd-nbd } @@ -106,8 +116,8 @@ local dev=$1 local pid=$2 - _sudo rbd-nbd unmap ${dev} - rbd-nbd list-mapped | expect_false grep "^${pid}\\b" || return 1 + _sudo rbd device --device-type nbd unmap ${dev} + rbd device --device-type nbd list | expect_false grep "^${pid}\\b" || return 1 ps -C rbd-nbd | expect_false grep "^ *${pid}\\b" || return 1 # workaround possible race between unmap and following map @@ -125,19 +135,19 @@ expect_false rbd-nbd INVALIDCMD if [ `id -u` -ne 0 ] then - expect_false rbd-nbd map ${IMAGE} + expect_false rbd device --device-type nbd map ${IMAGE} fi -expect_false _sudo rbd-nbd map INVALIDIMAGE +expect_false _sudo rbd device --device-type nbd map INVALIDIMAGE expect_false _sudo rbd-nbd --device INVALIDDEV map ${IMAGE} # list format test -expect_false rbd-nbd --format INVALID list-mapped -rbd-nbd --format json --pretty-format list-mapped -rbd-nbd --format xml list-mapped +expect_false rbd device --device-type nbd --format INVALID list +rbd device --device-type nbd --format json --pretty-format list +rbd device --device-type nbd --format xml list # map test using the first unused device -DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${IMAGE}` +get_pid ${POOL} # map test specifying the device expect_false _sudo rbd-nbd --device ${DEV} map ${POOL}/${IMAGE} dev1=${DEV} @@ -146,8 +156,8 @@ # XXX: race possible when the device is reused by other process DEV=`_sudo rbd-nbd --device ${dev1} map ${POOL}/${IMAGE}` [ "${DEV}" = "${dev1}" ] -rbd-nbd list-mapped | grep "${IMAGE}" -get_pid +rbd device --device-type nbd list | grep "${IMAGE}" +get_pid ${POOL} # read test [ "`dd if=${DATA} bs=1M | md5sum`" = "`_sudo dd if=${DEV} bs=1M | md5sum`" ] @@ -187,8 +197,8 @@ # read-only option test unmap_device ${DEV} ${PID} -DEV=`_sudo rbd-nbd map --read-only ${POOL}/${IMAGE}` -PID=$(rbd-nbd list-mapped | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \ +DEV=`_sudo rbd --device-type nbd map --read-only ${POOL}/${IMAGE}` +PID=$(rbd device --device-type nbd list | awk -v pool=${POOL} -v img=${IMAGE} -v dev=${DEV} \ '$2 == pool && $3 == img && $5 == dev {print $1}') test -n "${PID}" ps -p ${PID} -C rbd-nbd @@ -198,8 +208,8 @@ unmap_device ${DEV} ${PID} # exclusive option test -DEV=`_sudo rbd-nbd map --exclusive ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd --device-type nbd map --exclusive ${POOL}/${IMAGE}` +get_pid ${POOL} _sudo dd if=${DATA} of=${DEV} bs=1M oflag=direct expect_false timeout 10 \ @@ -209,49 +219,68 @@ rbd bench ${IMAGE} --io-type write --io-size=1024 --io-total=1024 # unmap by image name test -DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${IMAGE}` +get_pid ${POOL} unmap_device ${IMAGE} ${PID} DEV= # map/unmap snap test rbd snap create ${POOL}/${IMAGE}@snap -DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}@snap` -get_pid +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${IMAGE}@snap` +get_pid ${POOL} unmap_device "${IMAGE}@snap" ${PID} DEV= # map/unmap namespace test rbd snap create ${POOL}/${NS}/${IMAGE}@snap -DEV=`_sudo rbd-nbd map ${POOL}/${NS}/${IMAGE}@snap` -get_pid ${NS} +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${NS}/${IMAGE}@snap` +get_pid ${POOL} ${NS} unmap_device "${POOL}/${NS}/${IMAGE}@snap" ${PID} DEV= # unmap by image name test 2 -DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${IMAGE}` +get_pid ${POOL} pid=$PID -DEV=`_sudo rbd-nbd map ${POOL}/${NS}/${IMAGE}` -get_pid ${NS} +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${NS}/${IMAGE}` +get_pid ${POOL} ${NS} unmap_device ${POOL}/${NS}/${IMAGE} ${PID} DEV= unmap_device ${POOL}/${IMAGE} ${pid} +# map/unmap test with just image name and expect image to come from default pool +if [ "${POOL}" = "rbd" ];then + DEV=`_sudo rbd device --device-type nbd map ${IMAGE}` + get_pid ${POOL} + unmap_device ${IMAGE} ${PID} + DEV= +fi + +# map/unmap test with just image name after changing default pool +rbd config global set global rbd_default_pool ${ANOTHER_POOL} +rbd create --size 10M ${IMAGE} +DEV=`_sudo rbd device --device-type nbd map ${IMAGE}` +get_pid ${ANOTHER_POOL} +unmap_device ${IMAGE} ${PID} +DEV= + +# reset +rbd config global rm global rbd_default_pool + # auto unmap test -DEV=`_sudo rbd-nbd map ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd device --device-type nbd map ${POOL}/${IMAGE}` +get_pid ${POOL} _sudo kill ${PID} for i in `seq 10`; do - rbd-nbd list-mapped | expect_false grep "^${PID} *${POOL} *${IMAGE}" && break + rbd device --device-type nbd list | expect_false grep "^${PID} *${POOL} *${IMAGE}" && break sleep 1 done -rbd-nbd list-mapped | expect_false grep "^${PID} *${POOL} *${IMAGE}" +rbd device --device-type nbd list | expect_false grep "^${PID} *${POOL} *${IMAGE}" # quiesce test QUIESCE_HOOK=${TEMPDIR}/quiesce.sh -DEV=`_sudo rbd-nbd map --quiesce --quiesce-hook ${QUIESCE_HOOK} ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd device --device-type nbd map --quiesce --quiesce-hook ${QUIESCE_HOOK} ${POOL}/${IMAGE}` +get_pid ${POOL} # test it fails if the hook does not exists test ! -e ${QUIESCE_HOOK} @@ -296,12 +325,12 @@ LOG_FILE=${TEMPDIR}/rbd-nbd.log if [ -n "${CEPH_SRC}" ]; then QUIESCE_HOOK=${CEPH_SRC}/tools/rbd_nbd/rbd-nbd_quiesce - DEV=`_sudo rbd-nbd map --quiesce --quiesce-hook ${QUIESCE_HOOK} \ + DEV=`_sudo rbd device --device-type nbd map --quiesce --quiesce-hook ${QUIESCE_HOOK} \ ${POOL}/${IMAGE} --log-file=${LOG_FILE}` else - DEV=`_sudo rbd-nbd map --quiesce ${POOL}/${IMAGE} --log-file=${LOG_FILE}` + DEV=`_sudo rbd device --device-type nbd map --quiesce ${POOL}/${IMAGE} --log-file=${LOG_FILE}` fi -get_pid +get_pid ${POOL} _sudo mkfs ${DEV} mkdir ${TEMPDIR}/mnt _sudo mount ${DEV} ${TEMPDIR}/mnt @@ -314,17 +343,17 @@ expect_false grep 'quiesce failed' ${LOG_FILE} # test detach/attach -DEV=`_sudo rbd-nbd map --try-netlink ${POOL}/${IMAGE}` -get_pid +DEV=`_sudo rbd device --device-type nbd --options try-netlink map ${POOL}/${IMAGE}` +get_pid ${POOL} _sudo mount ${DEV} ${TEMPDIR}/mnt _sudo rbd-nbd detach ${POOL}/${IMAGE} -expect_false get_pid +expect_false get_pid ${POOL} _sudo rbd-nbd attach --device ${DEV} ${POOL}/${IMAGE} -get_pid +get_pid ${POOL} _sudo rbd-nbd detach ${DEV} -expect_false get_pid +expect_false get_pid ${POOL} _sudo rbd-nbd attach --device ${DEV} ${POOL}/${IMAGE} -get_pid +get_pid ${POOL} ls ${TEMPDIR}/mnt/ dd if=${TEMPDIR}/mnt/test of=/dev/null bs=1M count=1 _sudo dd if=${DATA} of=${TEMPDIR}/mnt/test1 bs=1M count=1 oflag=direct diff -Nru ceph-16.2.5/qa/workunits/rgw/s3_utilities.pm ceph-16.2.6/qa/workunits/rgw/s3_utilities.pm --- ceph-16.2.5/qa/workunits/rgw/s3_utilities.pm 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/qa/workunits/rgw/s3_utilities.pm 2021-09-16 14:27:19.000000000 +0000 @@ -134,15 +134,28 @@ return 0; } +# Read PRETTY_NAME from /etc/os-release +sub os_pretty_name +{ + open(FH, '<', '/etc/os-release') or die $!; + while (my $line = ) { + chomp $line; + if ($line =~ /^\s*PRETTY_NAME=\"?([^"]*)\"?/) { + return $1; + } + } + close(FH); +} + + # Function to get the Ceph and distro info sub ceph_os_info { my $ceph_v = get_command_output ( "ceph -v" ); my @ceph_arr = split(" ",$ceph_v); $ceph_v = "Ceph Version: $ceph_arr[2]"; - my $os_distro = get_command_output ( "lsb_release -d" ); - my @os_arr = split(":",$os_distro); - $os_distro = "Linux Flavor:$os_arr[1]"; + my $os_distro = os_pretty_name(); + $os_distro = "Linux Flavor:$os_distro"; return ($ceph_v, $os_distro); } diff -Nru ceph-16.2.5/README.aix ceph-16.2.6/README.aix --- ceph-16.2.5/README.aix 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/README.aix 2021-09-16 14:27:19.000000000 +0000 @@ -19,7 +19,6 @@ gettext less perl - gdbm pcre rsync zlib diff -Nru ceph-16.2.5/run-make-check.sh ceph-16.2.6/run-make-check.sh --- ceph-16.2.5/run-make-check.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/run-make-check.sh 2021-09-16 14:27:19.000000000 +0000 @@ -40,7 +40,7 @@ CHECK_MAKEOPTS=${CHECK_MAKEOPTS:-$DEFAULT_MAKEOPTS} if in_jenkins; then - if ! ctest $CHECK_MAKEOPTS --no-compress-output --output-on-failure -T Test; then + if ! ctest $CHECK_MAKEOPTS --no-compress-output --output-on-failure --test-output-size-failed 1024000 -T Test; then # do not return failure, as the jenkins publisher will take care of this rm -fr ${TMPDIR:-/tmp}/ceph-asok.* fi @@ -67,7 +67,7 @@ fi FOR_MAKE_CHECK=1 prepare # Init defaults after deps are installed. - local cmake_opts=" -DWITH_PYTHON3=3 -DWITH_GTEST_PARALLEL=ON -DWITH_FIO=ON -DWITH_CEPHFS_SHELL=ON -DWITH_SPDK=ON -DENABLE_GIT_VERSION=OFF" + local cmake_opts=" -DWITH_PYTHON3=3 -DWITH_GTEST_PARALLEL=ON -DWITH_FIO=ON -DWITH_CEPHFS_SHELL=ON -DWITH_GRAFANA=ON -DWITH_SPDK=ON -DENABLE_GIT_VERSION=OFF" if [ $WITH_SEASTAR ]; then cmake_opts+=" -DWITH_SEASTAR=ON" fi diff -Nru ceph-16.2.5/src/blk/CMakeLists.txt ceph-16.2.6/src/blk/CMakeLists.txt --- ceph-16.2.5/src/blk/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/blk/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -25,7 +25,7 @@ zoned/HMSMRDevice.cc) endif() -add_library(blk ${libblk_srcs}) +add_library(blk STATIC ${libblk_srcs}) target_include_directories(blk PRIVATE "./") if(HAVE_LIBAIO) diff -Nru ceph-16.2.5/src/cephadm/cephadm ceph-16.2.6/src/cephadm/cephadm --- ceph-16.2.5/src/cephadm/cephadm 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cephadm/cephadm 2021-09-16 14:27:19.000000000 +0000 @@ -31,7 +31,7 @@ import ssl from enum import Enum -from typing import Dict, List, Tuple, Optional, Union, Any, NoReturn, Callable, IO +from typing import Dict, List, Tuple, Optional, Union, Any, NoReturn, Callable, IO, Sequence, TypeVar, cast, Set import re import uuid @@ -45,14 +45,18 @@ from urllib.request import urlopen from pathlib import Path +FuncT = TypeVar('FuncT', bound=Callable) + # Default container images ----------------------------------------------------- -DEFAULT_IMAGE = 'docker.io/ceph/ceph:v16' +DEFAULT_IMAGE = 'quay.io/ceph/ceph:v16' DEFAULT_IMAGE_IS_MASTER = False DEFAULT_IMAGE_RELEASE = 'pacific' -DEFAULT_PROMETHEUS_IMAGE = 'docker.io/prom/prometheus:v2.18.1' -DEFAULT_NODE_EXPORTER_IMAGE = 'docker.io/prom/node-exporter:v0.18.1' -DEFAULT_GRAFANA_IMAGE = 'docker.io/ceph/ceph-grafana:6.7.4' -DEFAULT_ALERT_MANAGER_IMAGE = 'docker.io/prom/alertmanager:v0.20.0' +DEFAULT_PROMETHEUS_IMAGE = 'quay.io/prometheus/prometheus:v2.18.1' +DEFAULT_NODE_EXPORTER_IMAGE = 'quay.io/prometheus/node-exporter:v0.18.1' +DEFAULT_ALERT_MANAGER_IMAGE = 'quay.io/prometheus/alertmanager:v0.20.0' +DEFAULT_GRAFANA_IMAGE = 'quay.io/ceph/ceph-grafana:6.7.4' +DEFAULT_HAPROXY_IMAGE = 'docker.io/library/haproxy:2.3' +DEFAULT_KEEPALIVED_IMAGE = 'docker.io/arcts/keepalived' DEFAULT_REGISTRY = 'docker.io' # normalize unqualified digests to this # ------------------------------------------------------------------------------ @@ -104,7 +108,7 @@ class BaseConfig: - def __init__(self): + def __init__(self) -> None: self.image: str = '' self.docker: bool = False self.data_dir: str = DATA_DIR @@ -122,7 +126,7 @@ self.container_init: bool = CONTAINER_INIT self.container_engine: Optional[ContainerEngine] = None - def set_from_args(self, args: argparse.Namespace): + def set_from_args(self, args: argparse.Namespace) -> None: argdict: Dict[str, Any] = vars(args) for k, v in argdict.items(): if hasattr(self, k): @@ -131,7 +135,7 @@ class CephadmContext: - def __init__(self): + def __init__(self) -> None: self.__dict__['_args'] = None self.__dict__['_conf'] = BaseConfig() @@ -163,28 +167,29 @@ class ContainerEngine: - def __init__(self): + def __init__(self) -> None: self.path = find_program(self.EXE) + @classmethod @property - def EXE(self) -> str: + def EXE(cls) -> str: raise NotImplementedError() class Podman(ContainerEngine): EXE = 'podman' - def __init__(self): + def __init__(self) -> None: super().__init__() - self._version = None + self._version: Optional[Tuple[int, ...]] = None @property - def version(self): + def version(self) -> Tuple[int, ...]: if self._version is None: raise RuntimeError('Please call `get_version` first') return self._version - def get_version(self, ctx: CephadmContext): + def get_version(self, ctx: CephadmContext) -> None: out, _, _ = call_throws(ctx, [self.path, 'version', '--format', '{{.Client.Version}}']) self._version = _parse_podman_version(out) @@ -639,7 +644,7 @@ """Defines an HAproxy container""" daemon_type = 'haproxy' required_files = ['haproxy.cfg'] - default_image = 'haproxy' + default_image = DEFAULT_HAPROXY_IMAGE def __init__(self, ctx: CephadmContext, @@ -702,7 +707,7 @@ cname = '%s-%s' % (cname, desc) return cname - def extract_uid_gid_haproxy(self): + def extract_uid_gid_haproxy(self) -> Tuple[int, int]: # better directory for this? return extract_uid_gid(self.ctx, file_path='/var/lib') @@ -726,7 +731,7 @@ """Defines an Keepalived container""" daemon_type = 'keepalived' required_files = ['keepalived.conf'] - default_image = 'arcts/keepalived' + default_image = DEFAULT_KEEPALIVED_IMAGE def __init__(self, ctx: CephadmContext, @@ -805,7 +810,7 @@ 'net.ipv4.ip_nonlocal_bind = 1', ] - def extract_uid_gid_keepalived(self): + def extract_uid_gid_keepalived(self) -> Tuple[int, int]: # better directory for this? return extract_uid_gid(self.ctx, file_path='/var/lib') @@ -1070,34 +1075,34 @@ seconds. """ - def __init__(self, lock_file): + def __init__(self, lock_file: str) -> None: """ """ #: The path of the file lock. self.lock_file = lock_file return None - def __str__(self): + def __str__(self) -> str: temp = "The file lock '{}' could not be acquired."\ .format(self.lock_file) return temp class _Acquire_ReturnProxy(object): - def __init__(self, lock): + def __init__(self, lock: 'FileLock') -> None: self.lock = lock return None - def __enter__(self): + def __enter__(self) -> 'FileLock': return self.lock - def __exit__(self, exc_type, exc_value, traceback): + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: self.lock.release() return None class FileLock(object): - def __init__(self, ctx: CephadmContext, name, timeout=-1): + def __init__(self, ctx: CephadmContext, name: str, timeout: int = -1) -> None: if not os.path.exists(LOCK_DIR): os.mkdir(LOCK_DIR, 0o700) self._lock_file = os.path.join(LOCK_DIR, name + '.lock') @@ -1116,10 +1121,10 @@ return None @property - def is_locked(self): + def is_locked(self) -> bool: return self._lock_file_fd is not None - def acquire(self, timeout=None, poll_intervall=0.05): + def acquire(self, timeout: Optional[int] = None, poll_intervall: float = 0.05) -> _Acquire_ReturnProxy: """ Acquires the file lock or fails with a :exc:`Timeout` error. .. code-block:: python @@ -1186,7 +1191,7 @@ raise return _Acquire_ReturnProxy(lock=self) - def release(self, force=False): + def release(self, force: bool = False) -> None: """ Releases the file lock. Please note, that the lock is only completly released, if the lock @@ -1200,29 +1205,32 @@ self._lock_counter -= 1 if self._lock_counter == 0 or force: - lock_id = id(self) - lock_filename = self._lock_file + # lock_id = id(self) + # lock_filename = self._lock_file - logger.debug('Releasing lock %s on %s', lock_id, lock_filename) + # Can't log in shutdown: + # File "/usr/lib64/python3.9/logging/__init__.py", line 1175, in _open + # NameError: name 'open' is not defined + # logger.debug('Releasing lock %s on %s', lock_id, lock_filename) self._release() self._lock_counter = 0 - logger.debug('Lock %s released on %s', lock_id, lock_filename) + # logger.debug('Lock %s released on %s', lock_id, lock_filename) return None - def __enter__(self): + def __enter__(self) -> 'FileLock': self.acquire() return self - def __exit__(self, exc_type, exc_value, traceback): + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: self.release() return None - def __del__(self): + def __del__(self) -> None: self.release(force=True) return None - def _acquire(self): + def _acquire(self) -> None: open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC fd = os.open(self._lock_file, open_mode) @@ -1234,7 +1242,7 @@ self._lock_file_fd = fd return None - def _release(self): + def _release(self) -> None: # Do not remove the lockfile: # # https://github.com/benediktschmitt/py-filelock/issues/31 @@ -1276,7 +1284,7 @@ on amount of spawn processes. """ - def __init__(self): + def __init__(self) -> None: self._pid_counter = itertools.count(0) self._threads = {} @@ -1384,7 +1392,7 @@ desc: Optional[str] = None, verbosity: CallVerbosity = CallVerbosity.VERBOSE_ON_FAILURE, timeout: Optional[int] = DEFAULT_TIMEOUT, - **kwargs) -> Tuple[str, str, int]: + **kwargs: Any) -> Tuple[str, str, int]: """ Wrap subprocess.Popen to @@ -1417,7 +1425,8 @@ process = await asyncio.create_subprocess_exec( *command, stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE) + stderr=asyncio.subprocess.PIPE, + env=os.environ.copy()) assert process.stdout assert process.stderr try: @@ -1447,7 +1456,7 @@ desc: Optional[str] = None, verbosity: CallVerbosity = CallVerbosity.VERBOSE_ON_FAILURE, timeout: Optional[int] = DEFAULT_TIMEOUT, - **kwargs) -> Tuple[str, str, int]: + **kwargs: Any) -> Tuple[str, str, int]: out, err, ret = call(ctx, command, desc, verbosity, timeout, **kwargs) if ret: raise RuntimeError('Failed command: %s' % ' '.join(command)) @@ -1466,14 +1475,14 @@ raise TimeoutExpired(msg) try: - return subprocess.call(command, timeout=timeout) + return subprocess.call(command, timeout=timeout, env=os.environ.copy()) except subprocess.TimeoutExpired: raise_timeout(command, timeout) ################################## -def json_loads_retry(cli_func): +def json_loads_retry(cli_func: Callable[[], str]) -> Any: for sleep_secs in [1, 4, 4]: try: return json.loads(cli_func()) @@ -1578,7 +1587,7 @@ def _parse_podman_version(version_str): # type: (str) -> Tuple[int, ...] - def to_int(val, org_e=None): + def to_int(val: str, org_e: Optional[Exception] = None) -> int: if not val and org_e: raise org_e try: @@ -1642,17 +1651,33 @@ return True -def infer_fsid(func): +def validate_fsid(func: FuncT) -> FuncT: + @wraps(func) + def _validate_fsid(ctx: CephadmContext) -> Any: + if 'fsid' in ctx and ctx.fsid: + if not is_fsid(ctx.fsid): + raise Error('not an fsid: %s' % ctx.fsid) + return func(ctx) + return cast(FuncT, _validate_fsid) + + +def infer_fsid(func: FuncT) -> FuncT: """ If we only find a single fsid in /var/lib/ceph/*, use that """ + @infer_config @wraps(func) - def _infer_fsid(ctx: CephadmContext): - if ctx.fsid: + def _infer_fsid(ctx: CephadmContext) -> Any: + if 'fsid' in ctx and ctx.fsid: logger.debug('Using specified fsid: %s' % ctx.fsid) return func(ctx) - fsids_set = set() + fsids = set() + + cp = read_config(ctx.config) + if cp.has_option('global', 'fsid'): + fsids.add(cp.get('global', 'fsid')) + daemon_list = list_daemons(ctx, detail=False) for daemon in daemon_list: if not is_fsid(daemon['fsid']): @@ -1660,11 +1685,11 @@ continue elif 'name' not in ctx or not ctx.name: # ctx.name not specified - fsids_set.add(daemon['fsid']) + fsids.add(daemon['fsid']) elif daemon['name'] == ctx.name: # ctx.name is a match - fsids_set.add(daemon['fsid']) - fsids = sorted(fsids_set) + fsids.add(daemon['fsid']) + fsids = sorted(fsids) if not fsids: # some commands do not always require an fsid @@ -1676,42 +1701,40 @@ raise Error('Cannot infer an fsid, one must be specified: %s' % fsids) return func(ctx) - return _infer_fsid + return cast(FuncT, _infer_fsid) -def infer_config(func): +def infer_config(func: FuncT) -> FuncT: """ If we find a MON daemon, use the config from that container """ @wraps(func) - def _infer_config(ctx: CephadmContext): + def _infer_config(ctx: CephadmContext) -> Any: + ctx.config = ctx.config if 'config' in ctx else None if ctx.config: logger.debug('Using specified config: %s' % ctx.config) return func(ctx) - config = None - if ctx.fsid: - name = ctx.name + if 'fsid' in ctx and ctx.fsid: + name = ctx.name if 'name' in ctx else None if not name: daemon_list = list_daemons(ctx, detail=False) for daemon in daemon_list: - if daemon['name'].startswith('mon.'): + if daemon.get('name', '').startswith('mon.'): name = daemon['name'] break if name: - config = '/var/lib/ceph/{}/{}/config'.format(ctx.fsid, - name) - if config: - logger.info('Inferring config %s' % config) - ctx.config = config + ctx.config = f'/var/lib/ceph/{ctx.fsid}/{name}/config' + if ctx.config: + logger.info('Inferring config %s' % ctx.config) elif os.path.exists(SHELL_DEFAULT_CONF): logger.debug('Using default config: %s' % SHELL_DEFAULT_CONF) ctx.config = SHELL_DEFAULT_CONF return func(ctx) - return _infer_config + return cast(FuncT, _infer_config) -def _get_default_image(ctx: CephadmContext): +def _get_default_image(ctx: CephadmContext) -> str: if DEFAULT_IMAGE_IS_MASTER: warn = """This is a development version of cephadm. For information regarding the latest stable release: @@ -1722,12 +1745,12 @@ return DEFAULT_IMAGE -def infer_image(func): +def infer_image(func: FuncT) -> FuncT: """ Use the most recent ceph image """ @wraps(func) - def _infer_image(ctx: CephadmContext): + def _infer_image(ctx: CephadmContext) -> Any: if not ctx.image: ctx.image = os.environ.get('CEPHADM_IMAGE') if not ctx.image: @@ -1736,12 +1759,12 @@ ctx.image = _get_default_image(ctx) return func(ctx) - return _infer_image + return cast(FuncT, _infer_image) -def default_image(func): +def default_image(func: FuncT) -> FuncT: @wraps(func) - def _default_image(ctx: CephadmContext): + def _default_image(ctx: CephadmContext) -> Any: if not ctx.image: if 'name' in ctx and ctx.name: type_ = ctx.name.split('.', 1)[0] @@ -1758,10 +1781,10 @@ return func(ctx) - return _default_image + return cast(FuncT, _default_image) -def get_last_local_ceph_image(ctx: CephadmContext, container_path: str): +def get_last_local_ceph_image(ctx: CephadmContext, container_path: str) -> Optional[str]: """ :return: The most recent local ceph image (already pulled) """ @@ -1920,7 +1943,7 @@ # copied from distutils -def find_executable(executable, path=None): +def find_executable(executable: str, path: Optional[str] = None) -> Optional[str]: """Tries to find 'executable' in the directories listed in 'path'. A string listing directories separated by 'os.pathsep'; defaults to os.environ['PATH']. Returns the complete filename or None if not found. @@ -1964,7 +1987,7 @@ return name -def find_container_engine(ctx: CephadmContext): +def find_container_engine(ctx: CephadmContext) -> Optional[ContainerEngine]: if ctx.docker: return Docker() else: @@ -1980,7 +2003,9 @@ # type: (CephadmContext) -> None engine = ctx.container_engine if not isinstance(engine, CONTAINER_PREFERENCE): - raise Error('Unable to locate any of %s' % [i.EXE for i in CONTAINER_PREFERENCE]) + # See https://github.com/python/mypy/issues/8993 + exes: List[str] = [i.EXE for i in CONTAINER_PREFERENCE] # type: ignore + raise Error('No container engine binary found ({}). Try run `apt/dnf/yum/zypper install `'.format(' or '.join(exes))) elif isinstance(engine, Podman): engine.get_version(ctx) if engine.version < MIN_PODMAN_VERSION: @@ -1998,7 +2023,7 @@ return 'ceph-%s@%s' % (fsid, daemon_type) -def get_unit_name_by_daemon_name(ctx: CephadmContext, fsid, name): +def get_unit_name_by_daemon_name(ctx: CephadmContext, fsid: str, name: str) -> str: daemon = get_daemon_description(ctx, fsid, name) try: return daemon['systemd_unit'] @@ -2059,12 +2084,19 @@ return False -def is_container_running(ctx: CephadmContext, name: str) -> bool: - out, err, ret = call(ctx, [ - ctx.container_engine.path, 'container', 'inspect', - '--format', '{{.State.Status}}', name - ]) - return out == 'running' +def is_container_running(ctx: CephadmContext, c: 'CephContainer') -> bool: + return bool(get_running_container_name(ctx, c)) + + +def get_running_container_name(ctx: CephadmContext, c: 'CephContainer') -> Optional[str]: + for name in [c.cname, c.old_cname]: + out, err, ret = call(ctx, [ + ctx.container_engine.path, 'container', 'inspect', + '--format', '{{.State.Status}}', name + ]) + if out.strip() == 'running': + return name + return None def get_legacy_config_fsid(cluster, legacy_dir=None): @@ -2173,7 +2205,9 @@ f.write(keyring) if daemon_type in Monitoring.components.keys(): - config_json: Dict[str, Any] = get_parm(ctx.config_json) + config_json: Dict[str, Any] = dict() + if 'config_json' in ctx: + config_json = get_parm(ctx.config_json) # Set up directories specific to the monitoring component config_dir = '' @@ -2361,6 +2395,7 @@ ceph_folder = pathify(ctx.shared_ceph_folder) if os.path.exists(ceph_folder): mounts[ceph_folder + '/src/ceph-volume/ceph_volume'] = '/usr/lib/python3.6/site-packages/ceph_volume' + mounts[ceph_folder + '/src/cephadm/cephadm'] = '/usr/sbin/cephadm' mounts[ceph_folder + '/src/pybind/mgr'] = '/usr/share/ceph/mgr' mounts[ceph_folder + '/src/python-common/ceph'] = '/usr/lib/python3.6/site-packages/ceph' mounts[ceph_folder + '/monitoring/grafana/dashboards'] = '/etc/grafana/dashboards/ceph-dashboard' @@ -2428,11 +2463,11 @@ entrypoint: str = '' name: str = '' ceph_args: List[str] = [] - envs: List[str] = [ - 'TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=134217728', - ] + envs: List[str] = [] host_network: bool = True + if daemon_type in Ceph.daemons: + envs.append('TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES=134217728') if container_args is None: container_args = [] if daemon_type in ['mon', 'osd']: @@ -2461,6 +2496,7 @@ envs.extend(NFSGanesha.get_container_envs()) elif daemon_type == HAproxy.daemon_type: name = '%s.%s' % (daemon_type, daemon_id) + container_args.extend(['--user=root']) # haproxy 2.4 defaults to a different user elif daemon_type == Keepalived.daemon_type: name = '%s.%s' % (daemon_type, daemon_id) envs.extend(Keepalived.get_container_envs()) @@ -2506,15 +2542,16 @@ if ctx.container_engine.version >= CGROUPS_SPLIT_PODMAN_VERSION: container_args.append('--cgroups=split') - return CephContainer( + return CephContainer.for_daemon( ctx, - image=ctx.image, + fsid=fsid, + daemon_type=daemon_type, + daemon_id=str(daemon_id), entrypoint=entrypoint, args=ceph_args + get_daemon_args(ctx, fsid, daemon_type, daemon_id), container_args=container_args, volume_mounts=get_container_mounts(ctx, fsid, daemon_type, daemon_id), bind_mounts=get_container_binds(ctx, fsid, daemon_type, daemon_id), - cname='ceph-%s-%s.%s' % (fsid, daemon_type, daemon_id), envs=envs, privileged=privileged, ptrace=ptrace, @@ -2623,6 +2660,7 @@ else: config_js = get_parm(ctx.config_json) assert isinstance(config_js, dict) + assert isinstance(daemon_id, str) cephadm_exporter = CephadmDaemon(ctx, fsid, daemon_id, port) cephadm_exporter.deploy_daemon_unit(config_js) @@ -2668,6 +2706,7 @@ # unit file, makes it easier to read and grok. file_obj.write('# ' + comment + '\n') # Sometimes, adding `--rm` to a run_cmd doesn't work. Let's remove the container manually + file_obj.write('! ' + ' '.join(container.rm_cmd(old_cname=True)) + ' 2> /dev/null\n') file_obj.write('! ' + ' '.join(container.rm_cmd()) + ' 2> /dev/null\n') # Sometimes, `podman rm` doesn't find the container. Then you'll have to add `--storage` if isinstance(ctx.container_engine, Podman): @@ -2675,6 +2714,10 @@ '! ' + ' '.join([shlex.quote(a) for a in container.rm_cmd(storage=True)]) + ' 2> /dev/null\n') + file_obj.write( + '! ' + + ' '.join([shlex.quote(a) for a in container.rm_cmd(old_cname=True, storage=True)]) + + ' 2> /dev/null\n') # container run command file_obj.write( @@ -2682,6 +2725,31 @@ + (' &' if background else '') + '\n') +def clean_cgroup(ctx: CephadmContext, fsid: str, unit_name: str) -> None: + # systemd may fail to cleanup cgroups from previous stopped unit, which will cause next "systemctl start" to fail. + # see https://tracker.ceph.com/issues/50998 + + CGROUPV2_PATH = Path('/sys/fs/cgroup') + if not (CGROUPV2_PATH / 'system.slice').exists(): + # Only unified cgroup is affected, skip if not the case + return + + slice_name = 'system-ceph\\x2d{}.slice'.format(fsid.replace('-', '\\x2d')) + cg_path = CGROUPV2_PATH / 'system.slice' / slice_name / f'{unit_name}.service' + if not cg_path.exists(): + return + + def cg_trim(path: Path) -> None: + for p in path.iterdir(): + if p.is_dir(): + cg_trim(p) + path.rmdir() + try: + cg_trim(cg_path) + except OSError: + logger.warning(f'Failed to trim old cgroups {cg_path}') + + def deploy_daemon_units( ctx: CephadmContext, fsid: str, @@ -2790,6 +2858,15 @@ os.rename(data_dir + '/unit.poststop.new', data_dir + '/unit.poststop') + # post-stop command(s) + with open(data_dir + '/unit.stop.new', 'w') as f: + f.write('! ' + ' '.join(c.stop_cmd()) + '\n') + f.write('! ' + ' '.join(c.stop_cmd(old_cname=True)) + '\n') + + os.fchmod(f.fileno(), 0o600) + os.rename(data_dir + '/unit.stop.new', + data_dir + '/unit.stop') + if c: with open(data_dir + '/unit.image.new', 'w') as f: f.write(c.image + '\n') @@ -2818,6 +2895,7 @@ if enable: call_throws(ctx, ['systemctl', 'enable', unit_name]) if start: + clean_cgroup(ctx, fsid, unit_name) call_throws(ctx, ['systemctl', 'start', unit_name]) @@ -2960,6 +3038,7 @@ # apply the sysctl settings if lines: + Path(ctx.sysctl_dir).mkdir(mode=0o755, exist_ok=True) _write(conf, lines) call_throws(ctx, ['sysctl', '--system']) @@ -3066,7 +3145,7 @@ LimitNPROC=1048576 EnvironmentFile=-/etc/environment ExecStart=/bin/bash {data_dir}/{fsid}/%i/unit.run -ExecStop=-{container_path} stop ceph-{fsid}-%i +ExecStop=-/bin/bash -c '{container_path} stop ceph-{fsid}-%i ; bash {data_dir}/{fsid}/%i/unit.stop' ExecStopPost=-/bin/bash {data_dir}/{fsid}/%i/unit.poststop KillMode=none Restart=on-failure @@ -3114,7 +3193,7 @@ self.entrypoint = entrypoint self.args = args self.volume_mounts = volume_mounts - self.cname = cname + self._cname = cname self.container_args = container_args self.envs = envs self.privileged = privileged @@ -3125,6 +3204,73 @@ self.memory_request = memory_request self.memory_limit = memory_limit + @classmethod + def for_daemon(cls, + ctx: CephadmContext, + fsid: str, + daemon_type: str, + daemon_id: str, + entrypoint: str, + args: List[str] = [], + volume_mounts: Dict[str, str] = {}, + container_args: List[str] = [], + envs: Optional[List[str]] = None, + privileged: bool = False, + ptrace: bool = False, + bind_mounts: Optional[List[List[str]]] = None, + init: Optional[bool] = None, + host_network: bool = True, + memory_request: Optional[str] = None, + memory_limit: Optional[str] = None, + ) -> 'CephContainer': + return cls( + ctx, + image=ctx.image, + entrypoint=entrypoint, + args=args, + volume_mounts=volume_mounts, + cname='ceph-%s-%s.%s' % (fsid, daemon_type, daemon_id), + container_args=container_args, + envs=envs, + privileged=privileged, + ptrace=ptrace, + bind_mounts=bind_mounts, + init=init, + host_network=host_network, + memory_request=memory_request, + memory_limit=memory_limit, + ) + + @property + def cname(self) -> str: + """ + podman adds the current container name to the /etc/hosts + file. Turns out, python's `socket.getfqdn()` differs from + `hostname -f`, when we have the container names containing + dots in it.: + + # podman run --name foo.bar.baz.com ceph/ceph /bin/bash + [root@sebastians-laptop /]# cat /etc/hosts + 127.0.0.1 localhost + ::1 localhost + 127.0.1.1 sebastians-laptop foo.bar.baz.com + [root@sebastians-laptop /]# hostname -f + sebastians-laptop + [root@sebastians-laptop /]# python3 -c 'import socket; print(socket.getfqdn())' + foo.bar.baz.com + + Fascinatingly, this doesn't happen when using dashes. + """ + return self._cname.replace('.', '-') + + @cname.setter + def cname(self, val: str) -> None: + self._cname = val + + @property + def old_cname(self) -> str: + return self._cname + def run_cmd(self) -> List[str]: cmd_args: List[str] = [ str(self.ctx.container_engine.path), @@ -3232,6 +3378,9 @@ def exec_cmd(self, cmd): # type: (List[str]) -> List[str] + cname = get_running_container_name(self.ctx, self) + if not cname: + raise Error('unable to find container "{}"'.format(self.cname)) return [ str(self.ctx.container_engine.path), 'exec', @@ -3239,22 +3388,23 @@ self.cname, ] + cmd - def rm_cmd(self, storage=False): - # type: (bool) -> List[str] + def rm_cmd(self, old_cname: bool = False, storage: bool = False) -> List[str]: ret = [ str(self.ctx.container_engine.path), 'rm', '-f', ] if storage: ret.append('--storage') - ret.append(self.cname) + if old_cname: + ret.append(self.old_cname) + else: + ret.append(self.cname) return ret - def stop_cmd(self): - # type () -> List[str] + def stop_cmd(self, old_cname: bool = False) -> List[str]: ret = [ str(self.ctx.container_engine.path), - 'stop', self.cname, + 'stop', self.old_cname if old_cname else self.cname, ] return ret @@ -3336,7 +3486,7 @@ return 0 -def normalize_image_digest(digest): +def normalize_image_digest(digest: str) -> str: # normal case: # ceph/ceph -> docker.io/ceph/ceph # edge cases that shouldn't ever come up: @@ -3437,7 +3587,8 @@ ctx.mon_ip = wrap_ipv6(ctx.mon_ip) hasport = r.findall(ctx.mon_ip) if hasport: - port = int(hasport[0]) + port_str = hasport[0] + port = int(port_str) if port == 6789: addr_arg = '[v1:%s]' % ctx.mon_ip elif port == 3300: @@ -3446,7 +3597,7 @@ logger.warning('Using msgr2 protocol for unrecognized port %d' % port) addr_arg = '[v2:%s]' % ctx.mon_ip - base_ip = ctx.mon_ip[0:-(len(str(port))) - 1] + base_ip = ctx.mon_ip[0:-(len(port_str)) - 1] check_ip_port(ctx, base_ip, port) else: base_ip = ctx.mon_ip @@ -3464,10 +3615,11 @@ if not hasport: raise Error('--mon-addrv value %s must include port number' % addr_arg) - port = int(hasport[0]) + port_str = hasport[0] + port = int(port_str) # strip off v1: or v2: prefix - addr = re.sub(r'^\w+:', '', addr) - base_ip = addr[0:-(len(str(port))) - 1] + addr = re.sub(r'^v\d+:', '', addr) + base_ip = addr[0:-(len(port_str)) - 1] check_ip_port(ctx, base_ip, port) else: raise Error('must specify --mon-ip or --mon-addrv') @@ -3606,7 +3758,7 @@ fsid: str, mon_id: str, bootstrap_keyring_path: str, monmap_path: str -): +) -> Tuple[str, str]: logger.info('Creating mon...') create_daemon_dirs(ctx, fsid, 'mon', mon_id, uid, gid) mon_dir = get_data_dir(fsid, ctx.data_dir, 'mon', mon_id) @@ -3649,7 +3801,7 @@ ctx: CephadmContext, mon_id: str, mon_dir: str, admin_keyring_path: str, config_path: str -): +) -> None: logger.info('Waiting for mon to start...') c = CephContainer( ctx, @@ -3772,7 +3924,7 @@ try: args = ['orch', 'host', 'add', host] if ctx.mon_ip: - args.append(ctx.mon_ip) + args.append(unwrap_ipv6(ctx.mon_ip)) cli(args) except RuntimeError as e: raise Error('Failed to add host <%s>: %s' % (host, e)) @@ -3790,8 +3942,6 @@ cli(['orch', 'apply', 'crash']) if not ctx.skip_monitoring_stack: - logger.info('Enabling mgr prometheus module...') - cli(['mgr', 'module', 'enable', 'prometheus']) for t in ['prometheus', 'grafana', 'node-exporter', 'alertmanager']: logger.info('Deploying %s service with default placement...' % t) cli(['orch', 'apply', t]) @@ -3904,6 +4054,13 @@ and not cp.has_option('mgr', 'mgr standby modules') ): cp.set('mgr', 'mgr_standby_modules', 'false') + if ctx.log_to_file: + cp.set('global', 'log_to_file', 'true') + cp.set('global', 'log_to_stderr', 'false') + cp.set('global', 'log_to_journald', 'false') + cp.set('global', 'mon_cluster_log_to_file', 'true') + cp.set('global', 'mon_cluster_log_to_stderr', 'false') + cp.set('global', 'mon_cluster_log_to_journald', 'false') cpf = StringIO() cp.write(cpf) @@ -4111,7 +4268,7 @@ {tmp.name: '/var/lib/ceph/user.conf:z'}) # wait for mgr to restart (after enabling a module) - def wait_for_mgr_restart(): + def wait_for_mgr_restart() -> None: # first get latest mgrmap epoch from the mon. try newer 'mgr # stat' command first, then fall back to 'mgr dump' if # necessary @@ -4218,7 +4375,7 @@ ################################## -def command_registry_login(ctx: CephadmContext): +def command_registry_login(ctx: CephadmContext) -> int: if ctx.registry_json: logger.info('Pulling custom registry login info from %s.' % ctx.registry_json) d = get_parm(ctx.registry_json) @@ -4244,7 +4401,7 @@ return 0 -def registry_login(ctx: CephadmContext, url, username, password): +def registry_login(ctx: CephadmContext, url: Optional[str], username: Optional[str], password: Optional[str]) -> None: logger.info('Logging into custom registry.') try: engine = ctx.container_engine @@ -4291,9 +4448,8 @@ redeploy = False unit_name = get_unit_name(ctx.fsid, daemon_type, daemon_id) - container_name = 'ceph-%s-%s.%s' % (ctx.fsid, daemon_type, daemon_id) (_, state, _) = check_unit(ctx, unit_name) - if state == 'running' or is_container_running(ctx, container_name): + if state == 'running' or is_container_running(ctx, CephContainer.for_daemon(ctx, ctx.fsid, daemon_type, daemon_id, 'bash')): redeploy = True if ctx.reconfig: @@ -4429,24 +4585,16 @@ ################################## -def fsid_conf_mismatch(ctx): - # type: (CephadmContext) -> bool - (config, _) = get_config_and_keyring(ctx) - if config: - for c in config.split('\n'): - if 'fsid = ' in c.strip(): - if 'fsid = ' + ctx.fsid != c.strip(): - return True - return False - - @infer_fsid @infer_config @infer_image +@validate_fsid def command_shell(ctx): # type: (CephadmContext) -> int - if fsid_conf_mismatch(ctx): - raise Error('fsid does not match ceph conf') + cp = read_config(ctx.config) + if cp.has_option('global', 'fsid') and \ + cp.get('global', 'fsid') != ctx.fsid: + raise Error('fsid does not match ceph.conf') if ctx.fsid: make_log_dir(ctx, ctx.fsid) @@ -4560,8 +4708,14 @@ @infer_fsid @infer_image +@validate_fsid def command_ceph_volume(ctx): # type: (CephadmContext) -> None + cp = read_config(ctx.config) + if cp.has_option('global', 'fsid') and \ + cp.get('global', 'fsid') != ctx.fsid: + raise Error('fsid does not match ceph.conf') + if ctx.fsid: make_log_dir(ctx, ctx.fsid) @@ -4638,13 +4792,13 @@ # call this directly, without our wrapper, so that we get an unmolested # stdout with logger prefixing. logger.debug('Running command: %s' % ' '.join(cmd)) - subprocess.call(cmd) # type: ignore + subprocess.call(cmd, env=os.environ.copy()) # type: ignore ################################## def list_networks(ctx): - # type: (CephadmContext) -> Dict[str,Dict[str,List[str]]] + # type: (CephadmContext) -> Dict[str,Dict[str, Set[str]]] # sadly, 18.04's iproute2 4.15.0-2ubun doesn't support the -j flag, # so we'll need to use a regex to parse 'ip' command output. @@ -4652,13 +4806,12 @@ # out, _, _ = call_throws(['ip', '-j', 'route', 'ls']) # j = json.loads(out) # for x in j: - res = _list_ipv4_networks(ctx) res.update(_list_ipv6_networks(ctx)) return res -def _list_ipv4_networks(ctx: CephadmContext): +def _list_ipv4_networks(ctx: CephadmContext) -> Dict[str, Dict[str, Set[str]]]: execstr: Optional[str] = find_executable('ip') if not execstr: raise FileNotFoundError("unable to find 'ip' command") @@ -4666,8 +4819,8 @@ return _parse_ipv4_route(out) -def _parse_ipv4_route(out): - r = {} # type: Dict[str,Dict[str,List[str]]] +def _parse_ipv4_route(out: str) -> Dict[str, Dict[str, Set[str]]]: + r = {} # type: Dict[str, Dict[str, Set[str]]] p = re.compile(r'^(\S+) dev (\S+) (.*)scope link (.*)src (\S+)') for line in out.splitlines(): m = p.findall(line) @@ -4679,12 +4832,12 @@ if net not in r: r[net] = {} if iface not in r[net]: - r[net][iface] = [] - r[net][iface].append(ip) + r[net][iface] = set() + r[net][iface].add(ip) return r -def _list_ipv6_networks(ctx: CephadmContext): +def _list_ipv6_networks(ctx: CephadmContext) -> Dict[str, Dict[str, Set[str]]]: execstr: Optional[str] = find_executable('ip') if not execstr: raise FileNotFoundError("unable to find 'ip' command") @@ -4693,8 +4846,8 @@ return _parse_ipv6_route(routes, ips) -def _parse_ipv6_route(routes, ips): - r = {} # type: Dict[str,Dict[str,List[str]]] +def _parse_ipv6_route(routes: str, ips: str) -> Dict[str, Dict[str, Set[str]]]: + r = {} # type: Dict[str, Dict[str, Set[str]]] route_p = re.compile(r'^(\S+) dev (\S+) proto (\S+) metric (\S+) .*pref (\S+)$') ip_p = re.compile(r'^\s+inet6 (\S+)/(.*)scope (.*)$') iface_p = re.compile(r'^(\d+): (\S+): (.*)$') @@ -4709,7 +4862,7 @@ if net not in r: r[net] = {} if iface not in r[net]: - r[net][iface] = [] + r[net][iface] = set() iface = None for line in ips.splitlines(): @@ -4726,7 +4879,7 @@ if ipaddress.ip_address(ip) in ipaddress.ip_network(n)] if net: assert(iface) - r[net[0]][iface].append(ip) + r[net[0]][iface].add(ip) return r @@ -4734,7 +4887,11 @@ def command_list_networks(ctx): # type: (CephadmContext) -> None r = list_networks(ctx) - print(json.dumps(r, indent=4)) + + def serialize_sets(obj: Any) -> Any: + return list(obj) if isinstance(obj, set) else obj + + print(json.dumps(r, indent=4, default=serialize_sets)) ################################## @@ -4790,14 +4947,7 @@ [container_path, 'stats', '--format', '{{.ID}},{{.MemUsage}}', '--no-stream'], verbosity=CallVerbosity.DEBUG ) - seen_memusage_cid_len = 0 - if not code: - for line in out.splitlines(): - (cid, usage) = line.split(',') - (used, limit) = usage.split(' / ') - seen_memusage[cid] = with_units_to_int(used) - if not seen_memusage_cid_len: - seen_memusage_cid_len = len(cid) + seen_memusage_cid_len, seen_memusage = _parse_mem_usage(code, out) # /var/lib/ceph if os.path.exists(data_dir): @@ -4860,12 +5010,7 @@ version = None start_stamp = None - cmd = [ - container_path, 'inspect', - '--format', '{{.Id}},{{.Config.Image}},{{.Image}},{{.Created}},{{index .Config.Labels "io.ceph.version"}}', - 'ceph-%s-%s' % (fsid, j) - ] - out, err, code = call(ctx, cmd, verbosity=CallVerbosity.DEBUG) + out, err, code = get_container_stats(ctx, container_path, fsid, daemon_type, daemon_id) if not code: (container_id, image_name, image_id, start, version) = out.strip().split(',') @@ -4985,6 +5130,24 @@ return ls +def _parse_mem_usage(code: int, out: str) -> Tuple[int, Dict[str, int]]: + # keep track of memory usage we've seen + seen_memusage = {} # type: Dict[str, int] + seen_memusage_cid_len = 0 + if not code: + for line in out.splitlines(): + (cid, usage) = line.split(',') + (used, limit) = usage.split(' / ') + try: + seen_memusage[cid] = with_units_to_int(used) + if not seen_memusage_cid_len: + seen_memusage_cid_len = len(cid) + except ValueError: + logger.info('unable to parse memory usage line\n>{}'.format(line)) + pass + return seen_memusage_cid_len, seen_memusage + + def get_daemon_description(ctx, fsid, name, detail=False, legacy_dir=None): # type: (CephadmContext, str, str, bool, Optional[str]) -> Dict[str, str] @@ -4996,6 +5159,21 @@ return d raise Error('Daemon not found: {}. See `cephadm ls`'.format(name)) + +def get_container_stats(ctx: CephadmContext, container_path: str, fsid: str, daemon_type: str, daemon_id: str) -> Tuple[str, str, int]: + c = CephContainer.for_daemon(ctx, fsid, daemon_type, daemon_id, 'bash') + out, err, code = '', '', -1 + for name in (c.cname, c.old_cname): + cmd = [ + container_path, 'inspect', + '--format', '{{.Id}},{{.Config.Image}},{{.Image}},{{.Created}},{{index .Config.Labels "io.ceph.version"}}', + name + ] + out, err, code = call(ctx, cmd, verbosity=CallVerbosity.DEBUG) + if not code: + break + return out, err, code + ################################## @@ -5427,7 +5605,7 @@ ################################## -def _zap(ctx, what): +def _zap(ctx: CephadmContext, what: str) -> None: mounts = get_container_mounts(ctx, ctx.fsid, 'clusterless-ceph-volume', None) c = CephContainer( ctx, @@ -5443,7 +5621,7 @@ @infer_image -def _zap_osds(ctx): +def _zap_osds(ctx: CephadmContext) -> None: # assume fsid lock already held # list @@ -5476,7 +5654,7 @@ logger.warning(f'Not zapping LVs (not implemented): {lv_names}') -def command_zap_osds(ctx): +def command_zap_osds(ctx: CephadmContext) -> None: if not ctx.force: raise Error('must pass --force to proceed: ' 'this command may destroy precious data!') @@ -5521,7 +5699,7 @@ call(ctx, ['systemctl', 'disable', unit_name], verbosity=CallVerbosity.DEBUG) - slice_name = 'system-%s.slice' % (('ceph-%s' % ctx.fsid).replace('-', '\\x2d')) + slice_name = 'system-ceph\\x2d{}.slice'.format(ctx.fsid.replace('-', '\\x2d')) call(ctx, ['systemctl', 'stop', slice_name], verbosity=CallVerbosity.DEBUG) @@ -5583,6 +5761,7 @@ 'ntpd.service', # el7 (at least) 'ntp.service', # 18.04 (at least) 'ntpsec.service', # 20.04 (at least) / buster + 'openntpd.service', # ubuntu / debian ] if not check_units(ctx, units, enabler): logger.warning('No time sync service is running; checked for %s' % units) @@ -5668,7 +5847,7 @@ class CustomValidation(argparse.Action): - def _check_name(self, values): + def _check_name(self, values: str) -> None: try: (daemon_type, daemon_id) = values.split('.', 1) except ValueError: @@ -5681,7 +5860,9 @@ 'name must declare the type of daemon e.g. ' '{}'.format(', '.join(daemons))) - def __call__(self, parser, namespace, values, option_string=None): + def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace, values: Union[str, Sequence[Any], None], + option_string: Optional[str] = None) -> None: + assert isinstance(values, str) if self.dest == 'name': self._check_name(values) setattr(namespace, self.dest, values) @@ -5723,7 +5904,8 @@ class Packager(object): def __init__(self, ctx: CephadmContext, - stable=None, version=None, branch=None, commit=None): + stable: Optional[str] = None, version: Optional[str] = None, + branch: Optional[str] = None, commit: Optional[str] = None): assert \ (stable and not version and not branch and not commit) or \ (not stable and version and not branch and not commit) or \ @@ -5735,13 +5917,19 @@ self.branch = branch self.commit = commit - def add_repo(self): + def add_repo(self) -> None: + raise NotImplementedError + + def rm_repo(self) -> None: + raise NotImplementedError + + def install(self, ls: List[str]) -> None: raise NotImplementedError - def rm_repo(self): + def install_podman(self) -> None: raise NotImplementedError - def query_shaman(self, distro, distro_version, branch, commit): + def query_shaman(self, distro: str, distro_version: Any, branch: Optional[str], commit: Optional[str]) -> str: # query shaman logger.info('Fetching repo metadata from shaman and chacra...') shaman_url = 'https://shaman.ceph.com/api/repos/ceph/{branch}/{sha1}/{distro}/{distro_version}/repo/?arch={arch}'.format( @@ -5765,7 +5953,7 @@ raise Error('%s, failed to fetch %s' % (err, chacra_url)) return chacra_response.read().decode('utf-8') - def repo_gpgkey(self): + def repo_gpgkey(self) -> Tuple[str, str]: if self.ctx.gpg_url: return self.ctx.gpg_url if self.stable or self.version: @@ -5773,7 +5961,7 @@ else: return 'https://download.ceph.com/keys/autobuild.gpg', 'autobuild' - def enable_service(self, service): + def enable_service(self, service: str) -> None: """ Start and enable the service (typically using systemd). """ @@ -5787,19 +5975,20 @@ } def __init__(self, ctx: CephadmContext, - stable, version, branch, commit, - distro, distro_version, distro_codename): + stable: Optional[str], version: Optional[str], branch: Optional[str], commit: Optional[str], + distro: Optional[str], distro_version: Optional[str], distro_codename: Optional[str]) -> None: super(Apt, self).__init__(ctx, stable=stable, version=version, branch=branch, commit=commit) + assert distro self.ctx = ctx self.distro = self.DISTRO_NAMES[distro] self.distro_codename = distro_codename self.distro_version = distro_version - def repo_path(self): + def repo_path(self) -> str: return '/etc/apt/sources.list.d/ceph.list' - def add_repo(self): + def add_repo(self) -> None: url, name = self.repo_gpgkey() logger.info('Installing repo GPG key from %s...' % url) @@ -5829,7 +6018,7 @@ self.update() - def rm_repo(self): + def rm_repo(self) -> None: for name in ['autobuild', 'release']: p = '/etc/apt/trusted.gpg.d/ceph.%s.gpg' % name if os.path.exists(p): @@ -5842,15 +6031,15 @@ if self.distro == 'ubuntu': self.rm_kubic_repo() - def install(self, ls): + def install(self, ls: List[str]) -> None: logger.info('Installing packages %s...' % ls) call_throws(self.ctx, ['apt-get', 'install', '-y'] + ls) - def update(self): + def update(self) -> None: logger.info('Updating package list...') call_throws(self.ctx, ['apt-get', 'update']) - def install_podman(self): + def install_podman(self) -> None: if self.distro == 'ubuntu': logger.info('Setting up repo for podman...') self.add_kubic_repo() @@ -5863,20 +6052,20 @@ logger.info('Podman did not work. Falling back to docker...') self.install(['docker.io']) - def kubic_repo_url(self): + def kubic_repo_url(self) -> str: return 'https://download.opensuse.org/repositories/devel:/kubic:/' \ 'libcontainers:/stable/xUbuntu_%s/' % self.distro_version - def kubic_repo_path(self): + def kubic_repo_path(self) -> str: return '/etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list' - def kubric_repo_gpgkey_url(self): + def kubric_repo_gpgkey_url(self) -> str: return '%s/Release.key' % self.kubic_repo_url() - def kubric_repo_gpgkey_path(self): + def kubric_repo_gpgkey_path(self) -> str: return '/etc/apt/trusted.gpg.d/kubic.release.gpg' - def add_kubic_repo(self): + def add_kubic_repo(self) -> None: url = self.kubric_repo_gpgkey_url() logger.info('Installing repo GPG key from %s...' % url) try: @@ -5895,7 +6084,7 @@ with open(self.kubic_repo_path(), 'w') as f: f.write(content) - def rm_kubic_repo(self): + def rm_kubic_repo(self) -> None: keyring = self.kubric_repo_gpgkey_path() if os.path.exists(keyring): logger.info('Removing repo GPG key %s...' % keyring) @@ -5913,14 +6102,17 @@ 'rhel': ('centos', 'el'), 'scientific': ('centos', 'el'), 'rocky': ('centos', 'el'), + 'almalinux': ('centos', 'el'), 'fedora': ('fedora', 'fc'), } def __init__(self, ctx: CephadmContext, - stable, version, branch, commit, - distro, distro_version): + stable: Optional[str], version: Optional[str], branch: Optional[str], commit: Optional[str], + distro: Optional[str], distro_version: Optional[str]) -> None: super(YumDnf, self).__init__(ctx, stable=stable, version=version, branch=branch, commit=commit) + assert distro + assert distro_version self.ctx = ctx self.major = int(distro_version.split('.')[0]) self.distro_normalized = self.DISTRO_NAMES[distro][0] @@ -5931,7 +6123,7 @@ else: self.tool = 'yum' - def custom_repo(self, **kw): + def custom_repo(self, **kw: Any) -> str: """ Repo files need special care in that a whole line should not be present if there is no value for it. Because we were using `format()` we could @@ -5987,10 +6179,10 @@ return '\n'.join(lines) - def repo_path(self): + def repo_path(self) -> str: return '/etc/yum.repos.d/ceph.repo' - def repo_baseurl(self): + def repo_baseurl(self) -> str: assert self.stable or self.version if self.version: return '%s/rpm-%s/%s' % (self.ctx.repo_url, self.version, @@ -5999,7 +6191,7 @@ return '%s/rpm-%s/%s' % (self.ctx.repo_url, self.stable, self.distro_code) - def add_repo(self): + def add_repo(self) -> None: if self.distro_code.startswith('fc'): raise Error('Ceph team does not build Fedora specific packages and therefore cannot add repos for this distro') if self.distro_code == 'el7': @@ -6035,15 +6227,15 @@ logger.info('Enabling EPEL...') call_throws(self.ctx, [self.tool, 'install', '-y', 'epel-release']) - def rm_repo(self): + def rm_repo(self) -> None: if os.path.exists(self.repo_path()): os.unlink(self.repo_path()) - def install(self, ls): + def install(self, ls: List[str]) -> None: logger.info('Installing packages %s...' % ls) call_throws(self.ctx, [self.tool, 'install', '-y'] + ls) - def install_podman(self): + def install_podman(self) -> None: self.install(['podman']) @@ -6055,10 +6247,11 @@ ] def __init__(self, ctx: CephadmContext, - stable, version, branch, commit, - distro, distro_version): + stable: Optional[str], version: Optional[str], branch: Optional[str], commit: Optional[str], + distro: Optional[str], distro_version: Optional[str]) -> None: super(Zypper, self).__init__(ctx, stable=stable, version=version, branch=branch, commit=commit) + assert distro is not None self.ctx = ctx self.tool = 'zypper' self.distro = 'opensuse' @@ -6066,7 +6259,7 @@ if 'tumbleweed' not in distro and distro_version is not None: self.distro_version = distro_version - def custom_repo(self, **kw): + def custom_repo(self, **kw: Any) -> str: """ See YumDnf for format explanation. """ @@ -6095,10 +6288,10 @@ return '\n'.join(lines) - def repo_path(self): + def repo_path(self) -> str: return '/etc/zypp/repos.d/ceph.repo' - def repo_baseurl(self): + def repo_baseurl(self) -> str: assert self.stable or self.version if self.version: return '%s/rpm-%s/%s' % (self.ctx.repo_url, @@ -6107,7 +6300,7 @@ return '%s/rpm-%s/%s' % (self.ctx.repo_url, self.stable, self.distro) - def add_repo(self): + def add_repo(self) -> None: if self.stable or self.version: content = '' for n, t in { @@ -6132,20 +6325,21 @@ with open(self.repo_path(), 'w') as f: f.write(content) - def rm_repo(self): + def rm_repo(self) -> None: if os.path.exists(self.repo_path()): os.unlink(self.repo_path()) - def install(self, ls): + def install(self, ls: List[str]) -> None: logger.info('Installing packages %s...' % ls) call_throws(self.ctx, [self.tool, 'in', '-y'] + ls) - def install_podman(self): + def install_podman(self) -> None: self.install(['podman']) def create_packager(ctx: CephadmContext, - stable=None, version=None, branch=None, commit=None): + stable: Optional[str] = None, version: Optional[str] = None, + branch: Optional[str] = None, commit: Optional[str] = None) -> Packager: distro, distro_version, distro_codename = get_distro() if distro in YumDnf.DISTRO_NAMES: return YumDnf(ctx, stable=stable, version=version, @@ -6163,7 +6357,7 @@ raise Error('Distro %s version %s not supported' % (distro, distro_version)) -def command_add_repo(ctx: CephadmContext): +def command_add_repo(ctx: CephadmContext) -> None: if ctx.version and ctx.release: raise Error('you can specify either --release or --version but not both') if not ctx.version and not ctx.release and not ctx.dev and not ctx.dev_commit: @@ -6185,12 +6379,12 @@ logger.info('Completed adding repo.') -def command_rm_repo(ctx: CephadmContext): +def command_rm_repo(ctx: CephadmContext) -> None: pkg = create_packager(ctx) pkg.rm_repo() -def command_install(ctx: CephadmContext): +def command_install(ctx: CephadmContext) -> None: pkg = create_packager(ctx) pkg.install(ctx.packages) @@ -6199,7 +6393,7 @@ def get_ipv4_address(ifname): # type: (str) -> str - def _extract(sock, offset): + def _extract(sock: socket.socket, offset: int) -> str: return socket.inet_ntop( socket.AF_INET, fcntl.ioctl( @@ -6296,7 +6490,6 @@ class HostFacts(): _dmi_path_list = ['/sys/class/dmi/id'] _nic_path_list = ['/sys/class/net'] - _selinux_path_list = ['/etc/selinux/config'] _apparmor_path_list = ['/etc/apparmor'] _disk_vendor_workarounds = { '0x1af4': 'Virtio Block Device' @@ -6653,23 +6846,30 @@ # type: () -> Dict[str, str] """Determine the security features enabled in the kernel - SELinux, AppArmor""" def _fetch_selinux() -> Dict[str, str]: - """Read the selinux config file to determine state""" + """Get the selinux status""" security = {} - for selinux_path in HostFacts._selinux_path_list: - if os.path.exists(selinux_path): - selinux_config = read_file([selinux_path]).splitlines() - security['type'] = 'SELinux' - for line in selinux_config: - if line.strip().startswith('#'): - continue - k, v = line.split('=') - security[k] = v - if security['SELINUX'].lower() == 'disabled': - security['description'] = 'SELinux: Disabled' - else: - security['description'] = 'SELinux: Enabled({}, {})'.format(security['SELINUX'], security['SELINUXTYPE']) - return security - return {} + try: + out, err, code = call(self.ctx, ['sestatus'], + verbosity=CallVerbosity.DEBUG) + security['type'] = 'SELinux' + status, mode, policy = '', '', '' + for line in out.split('\n'): + if line.startswith('SELinux status:'): + k, v = line.split(':') + status = v.strip() + elif line.startswith('Current mode:'): + k, v = line.split(':') + mode = v.strip() + elif line.startswith('Loaded policy name:'): + k, v = line.split(':') + policy = v.strip() + if status == 'disabled': + security['description'] = 'SELinux: Disabled' + else: + security['description'] = 'SELinux: Enabled({}, {})'.format(mode, policy) + except Exception as e: + logger.info('unable to get selinux status: %s' % e) + return security def _fetch_apparmor() -> Dict[str, str]: """Read the apparmor profiles directly, returning an overview of AppArmor status""" @@ -6722,7 +6922,7 @@ } @property - def selinux_enabled(self): + def selinux_enabled(self) -> bool: return (self.kernel_security['type'] == 'SELinux') and \ (self.kernel_security['description'] != 'SELinux: Disabled') @@ -6743,6 +6943,48 @@ return k_param + @staticmethod + def _process_net_data(tcp_file: str, protocol: str = 'tcp') -> List[int]: + listening_ports = [] + # Connections state documentation + # tcp - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp_states.h + # udp - uses 07 (TCP_CLOSE or UNCONN, since udp is stateless. test with netcat -ul ) + listening_state = { + 'tcp': '0A', + 'udp': '07' + } + + if protocol not in listening_state.keys(): + return [] + + if os.path.exists(tcp_file): + with open(tcp_file) as f: + tcp_data = f.readlines()[1:] + + for con in tcp_data: + con_info = con.strip().split() + if con_info[3] == listening_state[protocol]: + local_port = int(con_info[1].split(':')[1], 16) + listening_ports.append(local_port) + + return listening_ports + + @property + def tcp_ports_used(self) -> List[int]: + return HostFacts._process_net_data('/proc/net/tcp') + + @property + def tcp6_ports_used(self) -> List[int]: + return HostFacts._process_net_data('/proc/net/tcp6') + + @property + def udp_ports_used(self) -> List[int]: + return HostFacts._process_net_data('/proc/net/udp', 'udp') + + @property + def udp6_ports_used(self) -> List[int]: + return HostFacts._process_net_data('/proc/net/udp6', 'udp') + def dump(self): # type: () -> str """Return the attributes of this HostFacts object as json""" @@ -6756,7 +6998,7 @@ ################################## -def command_gather_facts(ctx: CephadmContext): +def command_gather_facts(ctx: CephadmContext) -> None: """gather_facts is intended to provide host releated metadata to the caller""" host = HostFacts(ctx) print(host.dump()) @@ -6768,7 +7010,7 @@ class CephadmCache: task_types = ['disks', 'daemons', 'host', 'http_server'] - def __init__(self): + def __init__(self) -> None: self.started_epoch_secs = time.time() self.tasks = { 'daemons': 'inactive', @@ -6776,21 +7018,21 @@ 'host': 'inactive', 'http_server': 'inactive', } - self.errors = [] - self.disks = {} - self.daemons = {} - self.host = {} + self.errors: list = [] + self.disks: dict = {} + self.daemons: dict = {} + self.host: dict = {} self.lock = RLock() @property - def health(self): + def health(self) -> dict: return { 'started_epoch_secs': self.started_epoch_secs, 'tasks': self.tasks, 'errors': self.errors, } - def to_json(self): + def to_json(self) -> dict: return { 'health': self.health, 'host': self.host, @@ -6798,14 +7040,14 @@ 'disks': self.disks, } - def update_health(self, task_type, task_status, error_msg=None): + def update_health(self, task_type: str, task_status: str, error_msg: Optional[str] = None) -> None: assert task_type in CephadmCache.task_types with self.lock: self.tasks[task_type] = task_status if error_msg: self.errors.append(error_msg) - def update_task(self, task_type, content): + def update_task(self, task_type: str, content: dict) -> None: assert task_type in CephadmCache.task_types assert isinstance(content, dict) with self.lock: @@ -6836,14 +7078,14 @@ class Decorators: @classmethod - def authorize(cls, f): + def authorize(cls, f: Any) -> Any: """Implement a basic token check. The token is installed at deployment time and must be provided to ensure we only respond to callers who know our token i.e. mgr """ - def wrapper(self, *args, **kwargs): + def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any: auth = self.headers.get('Authorization', None) if auth != 'Bearer ' + self.server.token: self.send_error(401) @@ -6852,7 +7094,7 @@ return wrapper - def _help_page(self): + def _help_page(self) -> str: return """ cephadm metadata exporter @@ -6888,14 +7130,14 @@ """.format(api_version=CephadmDaemonHandler.api_version) - def _fetch_root(self): + def _fetch_root(self) -> None: self.send_response(200) self.send_header('Content-type', 'text/html; charset=utf-8') self.end_headers() self.wfile.write(self._help_page().encode('utf-8')) @Decorators.authorize - def do_GET(self): + def do_GET(self) -> None: """Handle *all* GET requests""" if self.path == '/': @@ -6953,7 +7195,7 @@ self.end_headers() self.wfile.write(json.dumps({'message': bad_request_msg}).encode('utf-8')) - def log_message(self, format, *args): + def log_message(self, format: str, *args: Any) -> None: rqst = ' '.join(str(a) for a in args) logger.info(f'client:{self.address_string()} [{self.log_date_time_string()}] {rqst}') @@ -6973,7 +7215,7 @@ loop_delay = 1 thread_check_interval = 5 - def __init__(self, ctx: CephadmContext, fsid, daemon_id=None, port=None): + def __init__(self, ctx: CephadmContext, fsid: str, daemon_id: Optional[str] = None, port: Optional[int] = None) -> None: self.ctx = ctx self.fsid = fsid self.daemon_id = daemon_id @@ -6989,7 +7231,7 @@ self.token = read_file([os.path.join(self.daemon_path, CephadmDaemon.token_name)]) @classmethod - def validate_config(cls, config): + def validate_config(cls, config: dict) -> None: reqs = ', '.join(CephadmDaemon.config_requirements) errors = [] @@ -7022,11 +7264,11 @@ raise Error('Parameter errors : {}'.format(', '.join(errors))) @property - def port_active(self): + def port_active(self) -> bool: return port_in_use(self.ctx, self.port) @property - def can_run(self): + def can_run(self) -> bool: # if port is in use if self.port_active: self.errors.append(f'TCP port {self.port} already in use, unable to bind') @@ -7039,15 +7281,16 @@ return len(self.errors) == 0 @staticmethod - def _unit_name(fsid, daemon_id): + def _unit_name(fsid: str, daemon_id: str) -> str: return '{}.service'.format(get_unit_name(fsid, CephadmDaemon.daemon_type, daemon_id)) @property - def unit_name(self): + def unit_name(self) -> str: + assert self.daemon_id is not None return CephadmDaemon._unit_name(self.fsid, self.daemon_id) @property - def daemon_path(self): + def daemon_path(self) -> str: return os.path.join( self.ctx.data_dir, self.fsid, @@ -7055,12 +7298,12 @@ ) @property - def binary_path(self): + def binary_path(self) -> str: path = os.path.realpath(__file__) assert os.path.isfile(path) return path - def _handle_thread_exception(self, exc, thread_type): + def _handle_thread_exception(self, exc: Exception, thread_type: str) -> None: e_msg = f'{exc.__class__.__name__} exception: {str(exc)}' thread_info = getattr(self.cephadm_cache, thread_type) errors = thread_info.get('scrape_errors', []) @@ -7075,7 +7318,7 @@ } ) - def _scrape_host_facts(self, refresh_interval=10): + def _scrape_host_facts(self, refresh_interval: int = 10) -> None: ctr = 0 exception_encountered = False @@ -7118,7 +7361,7 @@ ctr += CephadmDaemon.loop_delay logger.info('host-facts thread stopped') - def _scrape_ceph_volume(self, refresh_interval=15): + def _scrape_ceph_volume(self, refresh_interval: int = 15) -> None: # we're invoking the ceph_volume command, so we need to set the args that it # expects to use self.ctx.command = 'inventory --format=json'.split() @@ -7177,7 +7420,7 @@ logger.info('ceph-volume thread stopped') - def _scrape_list_daemons(self, refresh_interval=20): + def _scrape_list_daemons(self, refresh_interval: int = 20) -> None: ctr = 0 exception_encountered = False while True: @@ -7217,7 +7460,7 @@ ctr += CephadmDaemon.loop_delay logger.info('list-daemons thread stopped') - def _create_thread(self, target, name, refresh_interval=None): + def _create_thread(self, target: Any, name: str, refresh_interval: Optional[int] = None) -> Thread: if refresh_interval: t = Thread(target=target, args=(refresh_interval,)) else: @@ -7234,7 +7477,7 @@ logger.info(f'{start_msg}') return t - def reload(self, *args): + def reload(self, *args: Any) -> None: """reload -HUP received This is a placeholder function only, and serves to provide the hook that could @@ -7242,12 +7485,12 @@ """ logger.info('Reload request received - ignoring, no action needed') - def shutdown(self, *args): + def shutdown(self, *args: Any) -> None: logger.info('Shutdown request received') self.stop = True self.http_server.shutdown() - def run(self): + def run(self) -> None: logger.info(f"cephadm exporter starting for FSID '{self.fsid}'") if not self.can_run: logger.error('Unable to start the exporter daemon') @@ -7302,7 +7545,7 @@ logger.info('Main http server thread stopped') @property - def unit_run(self): + def unit_run(self) -> str: return """set -e {py3} {bin_path} exporter --fsid {fsid} --id {daemon_id} --port {port} &""".format( @@ -7314,7 +7557,7 @@ ) @property - def unit_file(self): + def unit_file(self) -> str: docker = isinstance(self.ctx.container_engine, Docker) return """#generated by cephadm [Unit] @@ -7341,7 +7584,7 @@ docker_after=' docker.service' if docker else '', docker_requires='Requires=docker.service\n' if docker else '') - def deploy_daemon_unit(self, config=None): + def deploy_daemon_unit(self, config: Optional[dict] = None) -> None: """deploy a specific unit file for cephadm The normal deploy_daemon_units doesn't apply for this @@ -7361,8 +7604,11 @@ # we pick up the file from where the orchestrator placed it - otherwise we'll # copy it to the binary location for this cluster if not __file__ == '': - shutil.copy(__file__, - self.binary_path) + try: + shutil.copy(__file__, + self.binary_path) + except shutil.SameFileError: + pass with open(os.path.join(self.daemon_path, 'unit.run'), 'w') as f: f.write(self.unit_run) @@ -7385,7 +7631,7 @@ call_throws(self.ctx, ['systemctl', 'enable', '--now', self.unit_name]) @classmethod - def uninstall(cls, ctx: CephadmContext, fsid, daemon_type, daemon_id): + def uninstall(cls, ctx: CephadmContext, fsid: str, daemon_type: str, daemon_id: str) -> None: unit_name = CephadmDaemon._unit_name(fsid, daemon_id) unit_path = os.path.join(ctx.unit_dir, unit_name) unit_run = os.path.join(ctx.data_dir, fsid, f'{daemon_type}.{daemon_id}', 'unit.run') @@ -7423,7 +7669,7 @@ stdout, stderr, rc = call(ctx, ['systemctl', 'daemon-reload']) -def command_exporter(ctx: CephadmContext): +def command_exporter(ctx: CephadmContext) -> None: exporter = CephadmDaemon(ctx, ctx.fsid, daemon_id=ctx.id, port=ctx.port) if ctx.fsid not in os.listdir(ctx.data_dir): @@ -7446,7 +7692,7 @@ @infer_fsid -def command_maintenance(ctx: CephadmContext): +def command_maintenance(ctx: CephadmContext) -> str: if not ctx.fsid: raise Error('must pass --fsid to specify cluster') @@ -7495,6 +7741,7 @@ return 'failed - unable to start the target' else: return f'success - systemd target {target} enabled and started' + return f'success - systemd target {target} enabled and started' ################################## @@ -7874,7 +8121,6 @@ '--ssh-user', default='root', help='set user for SSHing to cluster hosts, passwordless sudo will be needed for non-root users') - parser_bootstrap.add_argument( '--skip-mon-network', action='store_true', @@ -7930,7 +8176,6 @@ parser_bootstrap.add_argument( '--apply-spec', help='Apply cluster spec after bootstrap (copy ssh key, add hosts and apply services)') - parser_bootstrap.add_argument( '--shared_ceph_folder', metavar='CEPH_SOURCE_FOLDER', @@ -7968,6 +8213,10 @@ '--single-host-defaults', action='store_true', help='adjust configuration defaults to suit a single-host cluster') + parser_bootstrap.add_argument( + '--log-to-file', + action='store_true', + help='configure cluster to log to traditional log files in /var/log/ceph/$fsid') parser_deploy = subparsers.add_parser( 'deploy', help='deploy a daemon') @@ -8136,7 +8385,7 @@ return parser -def _parse_args(av): +def _parse_args(av: List[str]) -> argparse.Namespace: parser = _get_parser() args = parser.parse_args(av) @@ -8193,7 +8442,7 @@ return ctx -def main(): +def main() -> None: # root? if os.geteuid() != 0: diff -Nru ceph-16.2.5/src/cephadm/tests/fixtures.py ceph-16.2.6/src/cephadm/tests/fixtures.py --- ceph-16.2.5/src/cephadm/tests/fixtures.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cephadm/tests/fixtures.py 2021-09-16 14:27:19.000000000 +0000 @@ -69,6 +69,8 @@ gid = os.getgid() with mock.patch('os.fchown'), \ + mock.patch('os.fchmod'), \ + mock.patch('platform.processor', return_value='x86_64'), \ mock.patch('cephadm.extract_uid_gid', return_value=(uid, gid)): fs.create_dir(cd.DATA_DIR) @@ -93,19 +95,21 @@ :param list_networks: mock 'list-networks' return :param hostname: mock 'socket.gethostname' return """ - if not list_networks: - list_networks = {} if not hostname: hostname = 'host1' - with mock.patch('cephadm.get_parm'), \ - mock.patch('cephadm.attempt_bind'), \ + with mock.patch('cephadm.attempt_bind'), \ mock.patch('cephadm.call', return_value=('', '', 0)), \ + mock.patch('cephadm.call_timeout', return_value=0), \ mock.patch('cephadm.find_executable', return_value='foo'), \ mock.patch('cephadm.is_available', return_value=True), \ mock.patch('cephadm.json_loads_retry', return_value={'epoch' : 1}), \ - mock.patch('cephadm.list_networks', return_value=list_networks), \ mock.patch('socket.gethostname', return_value=hostname): - ctx: cd.CephadmContext = cd.cephadm_init_ctx(cmd) - ctx.container_engine = container_engine - yield ctx + ctx: cd.CephadmContext = cd.cephadm_init_ctx(cmd) + ctx.container_engine = container_engine + if list_networks is not None: + with mock.patch('cephadm.list_networks', return_value=list_networks): + yield ctx + else: + yield ctx + diff -Nru ceph-16.2.5/src/cephadm/tests/test_cephadm.py ceph-16.2.6/src/cephadm/tests/test_cephadm.py --- ceph-16.2.5/src/cephadm/tests/test_cephadm.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cephadm/tests/test_cephadm.py 2021-09-16 14:27:19.000000000 +0000 @@ -1,6 +1,7 @@ # type: ignore import errno +import json import mock import os import pytest @@ -30,10 +31,20 @@ cd = SourceFileLoader('cephadm', 'cephadm').load_module() +def get_ceph_conf( + fsid='00000000-0000-0000-0000-0000deadbeef', + mon_host='[v2:192.168.1.1:3300/0,v1:192.168.1.1:6789/0]'): + return f''' +# minimal ceph.conf for {fsid} +[global] + fsid = {fsid} + mon_host = {mon_host} +''' + class TestCephAdm(object): def test_docker_unit_file(self): - ctx = mock.Mock() + ctx = cd.CephadmContext() ctx.container_engine = mock_docker() r = cd.get_unit_file(ctx, '9b9d7609-f4d5-4aba-94c8-effa764d96c9') assert 'Requires=docker.service' in r @@ -91,7 +102,7 @@ @mock.patch('socket.socket') @mock.patch('cephadm.logger') def test_check_ip_port_success(self, logger, _socket): - ctx = mock.Mock() + ctx = cd.CephadmContext() ctx.skip_ping_check = False # enables executing port check with `check_ip_port` for address, address_family in ( @@ -108,7 +119,7 @@ @mock.patch('socket.socket') @mock.patch('cephadm.logger') def test_check_ip_port_failure(self, logger, _socket): - ctx = mock.Mock() + ctx = cd.CephadmContext() ctx.skip_ping_check = False # enables executing port check with `check_ip_port` def os_error(errno): @@ -148,6 +159,11 @@ args = cd._parse_args(['--image', 'foo', 'version']) assert args.image == 'foo' + def test_parse_mem_usage(self): + cd.logger = mock.Mock() + len, summary = cd._parse_mem_usage(0, 'c6290e3f1489,-- / --') + assert summary == {} + def test_CustomValidation(self): assert cd._parse_args(['deploy', '--name', 'mon.a', '--fsid', 'fsid']) @@ -166,204 +182,6 @@ cd._parse_podman_version('inval.id') assert 'inval' in str(res.value) - @pytest.mark.parametrize("test_input, expected", [ - ( -""" -default via 192.168.178.1 dev enxd89ef3f34260 proto dhcp metric 100 -10.0.0.0/8 via 10.4.0.1 dev tun0 proto static metric 50 -10.3.0.0/21 via 10.4.0.1 dev tun0 proto static metric 50 -10.4.0.1 dev tun0 proto kernel scope link src 10.4.0.2 metric 50 -137.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 -138.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 -139.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 -140.1.0.0/17 via 10.4.0.1 dev tun0 proto static metric 50 -141.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 -169.254.0.0/16 dev docker0 scope link metric 1000 -172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 -192.168.39.0/24 dev virbr1 proto kernel scope link src 192.168.39.1 linkdown -192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown -192.168.178.0/24 dev enxd89ef3f34260 proto kernel scope link src 192.168.178.28 metric 100 -192.168.178.1 dev enxd89ef3f34260 proto static scope link metric 100 -195.135.221.12 via 192.168.178.1 dev enxd89ef3f34260 proto static metric 100 -""", - { - '10.4.0.1': {'tun0': ['10.4.0.2']}, - '172.17.0.0/16': {'docker0': ['172.17.0.1']}, - '192.168.39.0/24': {'virbr1': ['192.168.39.1']}, - '192.168.122.0/24': {'virbr0': ['192.168.122.1']}, - '192.168.178.0/24': {'enxd89ef3f34260': ['192.168.178.28']} - } - ), ( -""" -default via 10.3.64.1 dev eno1 proto static metric 100 -10.3.64.0/24 dev eno1 proto kernel scope link src 10.3.64.23 metric 100 -10.3.64.0/24 dev eno1 proto kernel scope link src 10.3.64.27 metric 100 -10.88.0.0/16 dev cni-podman0 proto kernel scope link src 10.88.0.1 linkdown -172.21.0.0/20 via 172.21.3.189 dev tun0 -172.21.1.0/20 via 172.21.3.189 dev tun0 -172.21.2.1 via 172.21.3.189 dev tun0 -172.21.3.1 dev tun0 proto kernel scope link src 172.21.3.2 -172.21.4.0/24 via 172.21.3.1 dev tun0 -172.21.5.0/24 via 172.21.3.1 dev tun0 -172.21.6.0/24 via 172.21.3.1 dev tun0 -172.21.7.0/24 via 172.21.3.1 dev tun0 -192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown -""", - { - '10.3.64.0/24': {'eno1': ['10.3.64.23', '10.3.64.27']}, - '10.88.0.0/16': {'cni-podman0': ['10.88.0.1']}, - '172.21.3.1': {'tun0': ['172.21.3.2']}, - '192.168.122.0/24': {'virbr0': ['192.168.122.1']}} - ), - ]) - def test_parse_ipv4_route(self, test_input, expected): - assert cd._parse_ipv4_route(test_input) == expected - - @pytest.mark.parametrize("test_routes, test_ips, expected", [ - ( -""" -::1 dev lo proto kernel metric 256 pref medium -fe80::/64 dev eno1 proto kernel metric 100 pref medium -fe80::/64 dev br-3d443496454c proto kernel metric 256 linkdown pref medium -fe80::/64 dev tun0 proto kernel metric 256 pref medium -fe80::/64 dev br-4355f5dbb528 proto kernel metric 256 pref medium -fe80::/64 dev docker0 proto kernel metric 256 linkdown pref medium -fe80::/64 dev cni-podman0 proto kernel metric 256 linkdown pref medium -fe80::/64 dev veth88ba1e8 proto kernel metric 256 pref medium -fe80::/64 dev vethb6e5fc7 proto kernel metric 256 pref medium -fe80::/64 dev vethaddb245 proto kernel metric 256 pref medium -fe80::/64 dev vethbd14d6b proto kernel metric 256 pref medium -fe80::/64 dev veth13e8fd2 proto kernel metric 256 pref medium -fe80::/64 dev veth1d3aa9e proto kernel metric 256 pref medium -fe80::/64 dev vethe485ca9 proto kernel metric 256 pref medium -""", -""" -1: lo: mtu 65536 state UNKNOWN qlen 1000 - inet6 ::1/128 scope host - valid_lft forever preferred_lft forever -2: eno1: mtu 1500 state UP qlen 1000 - inet6 fe80::225:90ff:fee5:26e8/64 scope link noprefixroute - valid_lft forever preferred_lft forever -6: br-3d443496454c: mtu 1500 state DOWN - inet6 fe80::42:23ff:fe9d:ee4/64 scope link - valid_lft forever preferred_lft forever -7: br-4355f5dbb528: mtu 1500 state UP - inet6 fe80::42:6eff:fe35:41fe/64 scope link - valid_lft forever preferred_lft forever -8: docker0: mtu 1500 state DOWN - inet6 fe80::42:faff:fee6:40a0/64 scope link - valid_lft forever preferred_lft forever -11: tun0: mtu 1500 state UNKNOWN qlen 100 - inet6 fe80::98a6:733e:dafd:350/64 scope link stable-privacy - valid_lft forever preferred_lft forever -28: cni-podman0: mtu 1500 state DOWN qlen 1000 - inet6 fe80::3449:cbff:fe89:b87e/64 scope link - valid_lft forever preferred_lft forever -31: vethaddb245@if30: mtu 1500 state UP - inet6 fe80::90f7:3eff:feed:a6bb/64 scope link - valid_lft forever preferred_lft forever -33: veth88ba1e8@if32: mtu 1500 state UP - inet6 fe80::d:f5ff:fe73:8c82/64 scope link - valid_lft forever preferred_lft forever -35: vethbd14d6b@if34: mtu 1500 state UP - inet6 fe80::b44f:8ff:fe6f:813d/64 scope link - valid_lft forever preferred_lft forever -37: vethb6e5fc7@if36: mtu 1500 state UP - inet6 fe80::4869:c6ff:feaa:8afe/64 scope link - valid_lft forever preferred_lft forever -39: veth13e8fd2@if38: mtu 1500 state UP - inet6 fe80::78f4:71ff:fefe:eb40/64 scope link - valid_lft forever preferred_lft forever -41: veth1d3aa9e@if40: mtu 1500 state UP - inet6 fe80::24bd:88ff:fe28:5b18/64 scope link - valid_lft forever preferred_lft forever -43: vethe485ca9@if42: mtu 1500 state UP - inet6 fe80::6425:87ff:fe42:b9f0/64 scope link - valid_lft forever preferred_lft forever -""", - { - "fe80::/64": { - "eno1": [ - "fe80::225:90ff:fee5:26e8" - ], - "br-3d443496454c": [ - "fe80::42:23ff:fe9d:ee4" - ], - "tun0": [ - "fe80::98a6:733e:dafd:350" - ], - "br-4355f5dbb528": [ - "fe80::42:6eff:fe35:41fe" - ], - "docker0": [ - "fe80::42:faff:fee6:40a0" - ], - "cni-podman0": [ - "fe80::3449:cbff:fe89:b87e" - ], - "veth88ba1e8": [ - "fe80::d:f5ff:fe73:8c82" - ], - "vethb6e5fc7": [ - "fe80::4869:c6ff:feaa:8afe" - ], - "vethaddb245": [ - "fe80::90f7:3eff:feed:a6bb" - ], - "vethbd14d6b": [ - "fe80::b44f:8ff:fe6f:813d" - ], - "veth13e8fd2": [ - "fe80::78f4:71ff:fefe:eb40" - ], - "veth1d3aa9e": [ - "fe80::24bd:88ff:fe28:5b18" - ], - "vethe485ca9": [ - "fe80::6425:87ff:fe42:b9f0" - ] - } - } - ), - ( -""" -::1 dev lo proto kernel metric 256 pref medium -2001:1458:301:eb::100:1a dev ens20f0 proto kernel metric 100 pref medium -2001:1458:301:eb::/64 dev ens20f0 proto ra metric 100 pref medium -fd01:1458:304:5e::/64 dev ens20f0 proto ra metric 100 pref medium -fe80::/64 dev ens20f0 proto kernel metric 100 pref medium -default proto ra metric 100 - nexthop via fe80::46ec:ce00:b8a0:d3c8 dev ens20f0 weight 1 - nexthop via fe80::46ec:ce00:b8a2:33c8 dev ens20f0 weight 1 pref medium -""", -""" -1: lo: mtu 65536 state UNKNOWN qlen 1000 - inet6 ::1/128 scope host - valid_lft forever preferred_lft forever -2: ens20f0: mtu 1500 state UP qlen 1000 - inet6 2001:1458:301:eb::100:1a/128 scope global dynamic noprefixroute - valid_lft 590879sec preferred_lft 590879sec - inet6 fe80::2e60:cff:fef8:da41/64 scope link noprefixroute - valid_lft forever preferred_lft forever -""", - { - '2001:1458:301:eb::/64': { - 'ens20f0': [ - '2001:1458:301:eb::100:1a' - ], - }, - 'fe80::/64': { - 'ens20f0': ['fe80::2e60:cff:fef8:da41'], - }, - 'fd01:1458:304:5e::/64': { - 'ens20f0': [] - }, - } - ), - ]) - def test_parse_ipv6_route(self, test_routes, test_ips, expected): - assert cd._parse_ipv6_route(test_routes, test_ips) == expected - def test_is_ipv6(self): cd.logger = mock.Mock() for good in ("[::1]", "::1", @@ -522,6 +340,184 @@ s = 'ceph/ceph:latest' assert cd.normalize_image_digest(s) == f'{cd.DEFAULT_REGISTRY}/{s}' + @pytest.mark.parametrize('fsid, ceph_conf, list_daemons, result, err, ', + [ + ( + None, + None, + [], + None, + None, + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + [], + '00000000-0000-0000-0000-0000deadbeef', + None, + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + [ + {'fsid': '10000000-0000-0000-0000-0000deadbeef'}, + {'fsid': '20000000-0000-0000-0000-0000deadbeef'}, + ], + '00000000-0000-0000-0000-0000deadbeef', + None, + ), + ( + None, + None, + [ + {'fsid': '00000000-0000-0000-0000-0000deadbeef'}, + ], + '00000000-0000-0000-0000-0000deadbeef', + None, + ), + ( + None, + None, + [ + {'fsid': '10000000-0000-0000-0000-0000deadbeef'}, + {'fsid': '20000000-0000-0000-0000-0000deadbeef'}, + ], + None, + r'Cannot infer an fsid', + ), + ( + None, + get_ceph_conf(fsid='00000000-0000-0000-0000-0000deadbeef'), + [], + '00000000-0000-0000-0000-0000deadbeef', + None, + ), + ( + None, + get_ceph_conf(fsid='00000000-0000-0000-0000-0000deadbeef'), + [ + {'fsid': '00000000-0000-0000-0000-0000deadbeef'}, + ], + '00000000-0000-0000-0000-0000deadbeef', + None, + ), + ( + None, + get_ceph_conf(fsid='00000000-0000-0000-0000-0000deadbeef'), + [ + {'fsid': '10000000-0000-0000-0000-0000deadbeef'}, + {'fsid': '20000000-0000-0000-0000-0000deadbeef'}, + ], + None, + r'Cannot infer an fsid', + ), + ]) + @mock.patch('cephadm.call') + def test_infer_fsid(self, _call, fsid, ceph_conf, list_daemons, result, err, cephadm_fs): + # build the context + ctx = cd.CephadmContext() + ctx.fsid = fsid + + # mock the decorator + mock_fn = mock.Mock() + mock_fn.return_value = 0 + infer_fsid = cd.infer_fsid(mock_fn) + + # mock the ceph.conf file content + if ceph_conf: + f = cephadm_fs.create_file('ceph.conf', contents=ceph_conf) + ctx.config = f.path + + # test + with mock.patch('cephadm.list_daemons', return_value=list_daemons): + if err: + with pytest.raises(cd.Error, match=err): + infer_fsid(ctx) + else: + infer_fsid(ctx) + assert ctx.fsid == result + + @pytest.mark.parametrize('fsid, config, name, list_daemons, result, ', + [ + ( + None, + '/foo/bar.conf', + None, + [], + '/foo/bar.conf', + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + None, + [], + cd.SHELL_DEFAULT_CONF, + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + None, + [{'name': 'mon.a'}], + '/var/lib/ceph/00000000-0000-0000-0000-0000deadbeef/mon.a/config', + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + None, + [{'name': 'osd.0'}], + cd.SHELL_DEFAULT_CONF, + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + '/foo/bar.conf', + 'mon.a', + [{'name': 'mon.a'}], + '/foo/bar.conf', + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + 'mon.a', + [], + '/var/lib/ceph/00000000-0000-0000-0000-0000deadbeef/mon.a/config', + ), + ( + '00000000-0000-0000-0000-0000deadbeef', + None, + 'osd.0', + [], + '/var/lib/ceph/00000000-0000-0000-0000-0000deadbeef/osd.0/config', + ), + ( + None, + None, + None, + [], + cd.SHELL_DEFAULT_CONF, + ), + ]) + @mock.patch('cephadm.call') + def test_infer_config(self, _call, fsid, config, name, list_daemons, result, cephadm_fs): + # build the context + ctx = cd.CephadmContext() + ctx.fsid = fsid + ctx.config = config + ctx.name = name + + # mock the decorator + mock_fn = mock.Mock() + mock_fn.return_value = 0 + infer_config = cd.infer_config(mock_fn) + + # mock the shell config + cephadm_fs.create_file(cd.SHELL_DEFAULT_CONF) + + # test + with mock.patch('cephadm.list_daemons', return_value=list_daemons): + infer_config(ctx) + assert ctx.config == result + + class TestCustomContainer(unittest.TestCase): cc: cd.CustomContainer @@ -925,7 +921,8 @@ class TestMonitoring(object): @mock.patch('cephadm.call') def test_get_version_alertmanager(self, _call): - ctx = mock.Mock() + ctx = cd.CephadmContext() + ctx.container_engine = mock_podman() daemon_type = 'alertmanager' # binary `prometheus` @@ -943,7 +940,8 @@ @mock.patch('cephadm.call') def test_get_version_prometheus(self, _call): - ctx = mock.Mock() + ctx = cd.CephadmContext() + ctx.container_engine = mock_podman() daemon_type = 'prometheus' _call.return_value = '', '{}, version 0.16.1'.format(daemon_type), 0 version = cd.Monitoring.get_version(ctx, 'container_id', daemon_type) @@ -951,20 +949,14 @@ @mock.patch('cephadm.call') def test_get_version_node_exporter(self, _call): - ctx = mock.Mock() + ctx = cd.CephadmContext() + ctx.container_engine = mock_podman() daemon_type = 'node-exporter' _call.return_value = '', '{}, version 0.16.1'.format(daemon_type.replace('-', '_')), 0 version = cd.Monitoring.get_version(ctx, 'container_id', daemon_type) assert version == '0.16.1' - @mock.patch('cephadm.os.fchown') - @mock.patch('cephadm.get_parm') - @mock.patch('cephadm.makedirs') - @mock.patch('cephadm.open') - @mock.patch('cephadm.make_log_dir') - @mock.patch('cephadm.make_data_dir') - def test_create_daemon_dirs_prometheus(self, make_data_dir, make_log_dir, _open, makedirs, - get_parm, fchown): + def test_create_daemon_dirs_prometheus(self, cephadm_fs): """ Ensures the required and optional files given in the configuration are created and mapped correctly inside the container. Tests absolute and @@ -975,15 +967,14 @@ daemon_type = 'prometheus' uid, gid = 50, 50 daemon_id = 'home' - ctx = mock.Mock() + ctx = cd.CephadmContext() ctx.data_dir = '/somedir' - files = { + ctx.config_json = json.dumps({ 'files': { 'prometheus.yml': 'foo', '/etc/prometheus/alerting/ceph_alerts.yml': 'bar' } - } - get_parm.return_value = files + }) cd.create_daemon_dirs(ctx, fsid, @@ -1000,14 +991,17 @@ daemon_type=daemon_type, daemon_id=daemon_id ) - assert _open.call_args_list == [ - mock.call('{}/etc/prometheus/prometheus.yml'.format(prefix), 'w', - encoding='utf-8'), - mock.call('{}/etc/prometheus/alerting/ceph_alerts.yml'.format(prefix), 'w', - encoding='utf-8'), - ] - assert mock.call().__enter__().write('foo') in _open.mock_calls - assert mock.call().__enter__().write('bar') in _open.mock_calls + + expected = { + 'etc/prometheus/prometheus.yml': 'foo', + 'etc/prometheus/alerting/ceph_alerts.yml': 'bar', + } + + for file,content in expected.items(): + file = os.path.join(prefix, file) + assert os.path.exists(file) + with open(file) as f: + assert f.read() == content class TestBootstrap(object): @@ -1088,6 +1082,11 @@ {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, True, ), + ( + '192.168.1.1:0123', + {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, + True, + ), # IPv6 ( '::', @@ -1110,6 +1109,16 @@ True, ), ( + '[::ffff:c0a8:101]:1234', + {"ffff::/64": {"eth0": ["::ffff:c0a8:101"]}}, + True, + ), + ( + '[::ffff:c0a8:101]:0123', + {"ffff::/64": {"eth0": ["::ffff:c0a8:101"]}}, + True, + ), + ( '0000:0000:0000:0000:0000:FFFF:C0A8:0101', {"ffff::/64": {"eth0": ["::ffff:c0a8:101"]}}, True, @@ -1127,6 +1136,67 @@ retval = cd.command_bootstrap(ctx) assert retval == 0 + @pytest.mark.parametrize('mon_addrv, list_networks, err', + [ + # IPv4 + ( + '192.168.1.1', + {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, + r'must use square backets', + ), + ( + '[192.168.1.1]', + {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, + r'must include port number', + ), + ( + '[192.168.1.1:1234]', + {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, + None, + ), + ( + '[192.168.1.1:0123]', + {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, + None, + ), + ( + '[v2:192.168.1.1:3300,v1:192.168.1.1:6789]', + {'192.168.1.0/24': {'eth0': ['192.168.1.1']}}, + None, + ), + # IPv6 + ( + '[::ffff:192.168.1.1:1234]', + {'ffff::/64': {'eth0': ['::ffff:c0a8:101']}}, + None, + ), + ( + '[::ffff:192.168.1.1:0123]', + {'ffff::/64': {'eth0': ['::ffff:c0a8:101']}}, + None, + ), + ( + '[0000:0000:0000:0000:0000:FFFF:C0A8:0101:1234]', + {'ffff::/64': {'eth0': ['::ffff:c0a8:101']}}, + None, + ), + ( + '[v2:0000:0000:0000:0000:0000:FFFF:C0A8:0101:3300,v1:0000:0000:0000:0000:0000:FFFF:C0A8:0101:6789]', + {'ffff::/64': {'eth0': ['::ffff:c0a8:101']}}, + None, + ), + ]) + def test_mon_addrv(self, mon_addrv, list_networks, err, cephadm_fs): + cmd = self._get_cmd('--mon-addrv', mon_addrv) + if err: + with with_cephadm_ctx(cmd, list_networks=list_networks) as ctx: + with pytest.raises(cd.Error, match=err): + cd.command_bootstrap(ctx) + else: + with with_cephadm_ctx(cmd, list_networks=list_networks) as ctx: + retval = cd.command_bootstrap(ctx) + assert retval == 0 + def test_allow_fqdn_hostname(self, cephadm_fs): hostname = 'foo.bar' cmd = self._get_cmd( @@ -1164,3 +1234,230 @@ else: retval = cd.command_bootstrap(ctx) assert retval == 0 + + +class TestShell(object): + + def test_fsid(self, cephadm_fs): + fsid = '00000000-0000-0000-0000-0000deadbeef' + + cmd = ['shell', '--fsid', fsid] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.fsid == fsid + + cmd = ['shell', '--fsid', '00000000-0000-0000-0000-0000deadbeez'] + with with_cephadm_ctx(cmd) as ctx: + err = 'not an fsid' + with pytest.raises(cd.Error, match=err): + retval = cd.command_shell(ctx) + assert retval == 1 + assert ctx.fsid == None + + s = get_ceph_conf(fsid=fsid) + f = cephadm_fs.create_file('ceph.conf', contents=s) + + cmd = ['shell', '--fsid', fsid, '--config', f.path] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.fsid == fsid + + cmd = ['shell', '--fsid', '10000000-0000-0000-0000-0000deadbeef', '--config', f.path] + with with_cephadm_ctx(cmd) as ctx: + err = 'fsid does not match ceph.conf' + with pytest.raises(cd.Error, match=err): + retval = cd.command_shell(ctx) + assert retval == 1 + assert ctx.fsid == None + + def test_name(self, cephadm_fs): + cmd = ['shell', '--name', 'foo'] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + + cmd = ['shell', '--name', 'foo.bar'] + with with_cephadm_ctx(cmd) as ctx: + err = r'must pass --fsid' + with pytest.raises(cd.Error, match=err): + retval = cd.command_shell(ctx) + assert retval == 1 + + fsid = '00000000-0000-0000-0000-0000deadbeef' + cmd = ['shell', '--name', 'foo.bar', '--fsid', fsid] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + + def test_config(self, cephadm_fs): + cmd = ['shell'] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.config == None + + cephadm_fs.create_file(cd.SHELL_DEFAULT_CONF) + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.config == cd.SHELL_DEFAULT_CONF + + cmd = ['shell', '--config', 'foo'] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.config == 'foo' + + def test_keyring(self, cephadm_fs): + cmd = ['shell'] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.keyring == None + + cephadm_fs.create_file(cd.SHELL_DEFAULT_KEYRING) + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.keyring == cd.SHELL_DEFAULT_KEYRING + + cmd = ['shell', '--keyring', 'foo'] + with with_cephadm_ctx(cmd) as ctx: + retval = cd.command_shell(ctx) + assert retval == 0 + assert ctx.keyring == 'foo' + + +class TestCephVolume(object): + + @staticmethod + def _get_cmd(*args): + return [ + 'ceph-volume', + *args, + '--', 'inventory', '--format', 'json' + ] + + def test_noop(self, cephadm_fs): + cmd = self._get_cmd() + with with_cephadm_ctx(cmd) as ctx: + cd.command_ceph_volume(ctx) + assert ctx.fsid == None + assert ctx.config == None + assert ctx.keyring == None + assert ctx.config_json == None + + def test_fsid(self, cephadm_fs): + fsid = '00000000-0000-0000-0000-0000deadbeef' + + cmd = self._get_cmd('--fsid', fsid) + with with_cephadm_ctx(cmd) as ctx: + cd.command_ceph_volume(ctx) + assert ctx.fsid == fsid + + cmd = self._get_cmd('--fsid', '00000000-0000-0000-0000-0000deadbeez') + with with_cephadm_ctx(cmd) as ctx: + err = 'not an fsid' + with pytest.raises(cd.Error, match=err): + retval = cd.command_shell(ctx) + assert retval == 1 + assert ctx.fsid == None + + s = get_ceph_conf(fsid=fsid) + f = cephadm_fs.create_file('ceph.conf', contents=s) + + cmd = self._get_cmd('--fsid', fsid, '--config', f.path) + with with_cephadm_ctx(cmd) as ctx: + cd.command_ceph_volume(ctx) + assert ctx.fsid == fsid + + cmd = self._get_cmd('--fsid', '10000000-0000-0000-0000-0000deadbeef', '--config', f.path) + with with_cephadm_ctx(cmd) as ctx: + err = 'fsid does not match ceph.conf' + with pytest.raises(cd.Error, match=err): + cd.command_ceph_volume(ctx) + assert ctx.fsid == None + + def test_config(self, cephadm_fs): + cmd = self._get_cmd('--config', 'foo') + with with_cephadm_ctx(cmd) as ctx: + err = r'No such file or directory' + with pytest.raises(cd.Error, match=err): + cd.command_ceph_volume(ctx) + + cephadm_fs.create_file('bar') + cmd = self._get_cmd('--config', 'bar') + with with_cephadm_ctx(cmd) as ctx: + cd.command_ceph_volume(ctx) + assert ctx.config == 'bar' + + def test_keyring(self, cephadm_fs): + cmd = self._get_cmd('--keyring', 'foo') + with with_cephadm_ctx(cmd) as ctx: + err = r'No such file or directory' + with pytest.raises(cd.Error, match=err): + cd.command_ceph_volume(ctx) + + cephadm_fs.create_file('bar') + cmd = self._get_cmd('--keyring', 'bar') + with with_cephadm_ctx(cmd) as ctx: + cd.command_ceph_volume(ctx) + assert ctx.keyring == 'bar' + + +class TestIscsi: + def test_unit_run(self, cephadm_fs): + fsid = '9b9d7609-f4d5-4aba-94c8-effa764d96c9' + config_json = { + 'files': {'iscsi-gateway.cfg': ''} + } + with with_cephadm_ctx(['--image=ceph/ceph'], list_networks={}) as ctx: + import json + ctx.config_json = json.dumps(config_json) + ctx.fsid = fsid + cd.get_parm.return_value = config_json + iscsi = cd.CephIscsi(ctx, '9b9d7609-f4d5-4aba-94c8-effa764d96c9', 'daemon_id', config_json) + c = iscsi.get_tcmu_runner_container() + + cd.make_data_dir(ctx, fsid, 'iscsi', 'daemon_id') + cd.deploy_daemon_units( + ctx, + fsid, + 0, 0, + 'iscsi', + 'daemon_id', + c, + True, True + ) + + with open('/var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/unit.run') as f: + assert f.read() == """set -e +if ! grep -qs /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/configfs /proc/mounts; then mount -t configfs none /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/configfs; fi +# iscsi tcmu-runnter container +! /usr/bin/podman rm -f ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi.daemon_id-tcmu 2> /dev/null +! /usr/bin/podman rm -f ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi-daemon_id-tcmu 2> /dev/null +/usr/bin/podman run --rm --ipc=host --stop-signal=SIGTERM --net=host --entrypoint /usr/bin/tcmu-runner --privileged --group-add=disk --init --name ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi-daemon_id-tcmu -e CONTAINER_IMAGE=ceph/ceph -e NODE_NAME=host1 -e CEPH_USE_RANDOM_NONCE=1 -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/config:/etc/ceph/ceph.conf:z -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/keyring:/etc/ceph/keyring:z -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/iscsi-gateway.cfg:/etc/ceph/iscsi-gateway.cfg:z -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/configfs:/sys/kernel/config -v /var/log/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9:/var/log/rbd-target-api:z -v /dev:/dev --mount type=bind,source=/lib/modules,destination=/lib/modules,ro=true ceph/ceph & +# iscsi.daemon_id +! /usr/bin/podman rm -f ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi.daemon_id-tcmu 2> /dev/null +! /usr/bin/podman rm -f ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi-daemon_id-tcmu 2> /dev/null +/usr/bin/podman run --rm --ipc=host --stop-signal=SIGTERM --net=host --entrypoint /usr/bin/tcmu-runner --privileged --group-add=disk --init --name ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi-daemon_id-tcmu -e CONTAINER_IMAGE=ceph/ceph -e NODE_NAME=host1 -e CEPH_USE_RANDOM_NONCE=1 -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/config:/etc/ceph/ceph.conf:z -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/keyring:/etc/ceph/keyring:z -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/iscsi-gateway.cfg:/etc/ceph/iscsi-gateway.cfg:z -v /var/lib/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9/iscsi.daemon_id/configfs:/sys/kernel/config -v /var/log/ceph/9b9d7609-f4d5-4aba-94c8-effa764d96c9:/var/log/rbd-target-api:z -v /dev:/dev --mount type=bind,source=/lib/modules,destination=/lib/modules,ro=true ceph/ceph +""" + + def test_get_container(self): + """ + Due to a combination of socket.getfqdn() and podman's behavior to + add the container name into the /etc/hosts file, we cannot use periods + in container names. But we need to be able to detect old existing containers. + Assert this behaviour. I think we can remove this in Ceph R + """ + fsid = '9b9d7609-f4d5-4aba-94c8-effa764d96c9' + with with_cephadm_ctx(['--image=ceph/ceph'], list_networks={}) as ctx: + ctx.fsid = fsid + c = cd.get_container(ctx, fsid, 'iscsi', 'something') + assert c.cname == 'ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi-something' + assert c.old_cname == 'ceph-9b9d7609-f4d5-4aba-94c8-effa764d96c9-iscsi.something' + + + diff -Nru ceph-16.2.5/src/cephadm/tests/test_networks.py ceph-16.2.6/src/cephadm/tests/test_networks.py --- ceph-16.2.5/src/cephadm/tests/test_networks.py 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/src/cephadm/tests/test_networks.py 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,201 @@ +import json +from textwrap import dedent +from unittest import mock + +import pytest + +from tests.fixtures import with_cephadm_ctx, cephadm_fs + +with mock.patch('builtins.open', create=True): + from importlib.machinery import SourceFileLoader + cd = SourceFileLoader('cephadm', 'cephadm').load_module() + + +class TestCommandListNetworks: + @pytest.mark.parametrize("test_input, expected", [ + ( + dedent(""" + default via 192.168.178.1 dev enxd89ef3f34260 proto dhcp metric 100 + 10.0.0.0/8 via 10.4.0.1 dev tun0 proto static metric 50 + 10.3.0.0/21 via 10.4.0.1 dev tun0 proto static metric 50 + 10.4.0.1 dev tun0 proto kernel scope link src 10.4.0.2 metric 50 + 137.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 + 138.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 + 139.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 + 140.1.0.0/17 via 10.4.0.1 dev tun0 proto static metric 50 + 141.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50 + 169.254.0.0/16 dev docker0 scope link metric 1000 + 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 + 192.168.39.0/24 dev virbr1 proto kernel scope link src 192.168.39.1 linkdown + 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown + 192.168.178.0/24 dev enxd89ef3f34260 proto kernel scope link src 192.168.178.28 metric 100 + 192.168.178.1 dev enxd89ef3f34260 proto static scope link metric 100 + 195.135.221.12 via 192.168.178.1 dev enxd89ef3f34260 proto static metric 100 + """), + { + '10.4.0.1': {'tun0': {'10.4.0.2'}}, + '172.17.0.0/16': {'docker0': {'172.17.0.1'}}, + '192.168.39.0/24': {'virbr1': {'192.168.39.1'}}, + '192.168.122.0/24': {'virbr0': {'192.168.122.1'}}, + '192.168.178.0/24': {'enxd89ef3f34260': {'192.168.178.28'}} + } + ), ( + dedent(""" + default via 10.3.64.1 dev eno1 proto static metric 100 + 10.3.64.0/24 dev eno1 proto kernel scope link src 10.3.64.23 metric 100 + 10.3.64.0/24 dev eno1 proto kernel scope link src 10.3.64.27 metric 100 + 10.88.0.0/16 dev cni-podman0 proto kernel scope link src 10.88.0.1 linkdown + 172.21.0.0/20 via 172.21.3.189 dev tun0 + 172.21.1.0/20 via 172.21.3.189 dev tun0 + 172.21.2.1 via 172.21.3.189 dev tun0 + 172.21.3.1 dev tun0 proto kernel scope link src 172.21.3.2 + 172.21.4.0/24 via 172.21.3.1 dev tun0 + 172.21.5.0/24 via 172.21.3.1 dev tun0 + 172.21.6.0/24 via 172.21.3.1 dev tun0 + 172.21.7.0/24 via 172.21.3.1 dev tun0 + 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown + 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown + 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown + 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown + """), + { + '10.3.64.0/24': {'eno1': {'10.3.64.23', '10.3.64.27'}}, + '10.88.0.0/16': {'cni-podman0': {'10.88.0.1'}}, + '172.21.3.1': {'tun0': {'172.21.3.2'}}, + '192.168.122.0/24': {'virbr0': {'192.168.122.1'}} + } + ), + ]) + def test_parse_ipv4_route(self, test_input, expected): + assert cd._parse_ipv4_route(test_input) == expected + + @pytest.mark.parametrize("test_routes, test_ips, expected", [ + ( + dedent(""" + ::1 dev lo proto kernel metric 256 pref medium + fe80::/64 dev eno1 proto kernel metric 100 pref medium + fe80::/64 dev br-3d443496454c proto kernel metric 256 linkdown pref medium + fe80::/64 dev tun0 proto kernel metric 256 pref medium + fe80::/64 dev br-4355f5dbb528 proto kernel metric 256 pref medium + fe80::/64 dev docker0 proto kernel metric 256 linkdown pref medium + fe80::/64 dev cni-podman0 proto kernel metric 256 linkdown pref medium + fe80::/64 dev veth88ba1e8 proto kernel metric 256 pref medium + fe80::/64 dev vethb6e5fc7 proto kernel metric 256 pref medium + fe80::/64 dev vethaddb245 proto kernel metric 256 pref medium + fe80::/64 dev vethbd14d6b proto kernel metric 256 pref medium + fe80::/64 dev veth13e8fd2 proto kernel metric 256 pref medium + fe80::/64 dev veth1d3aa9e proto kernel metric 256 pref medium + fe80::/64 dev vethe485ca9 proto kernel metric 256 pref medium + """), + dedent(""" + 1: lo: mtu 65536 state UNKNOWN qlen 1000 + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: eno1: mtu 1500 state UP qlen 1000 + inet6 fe80::225:90ff:fee5:26e8/64 scope link noprefixroute + valid_lft forever preferred_lft forever + 6: br-3d443496454c: mtu 1500 state DOWN + inet6 fe80::42:23ff:fe9d:ee4/64 scope link + valid_lft forever preferred_lft forever + 7: br-4355f5dbb528: mtu 1500 state UP + inet6 fe80::42:6eff:fe35:41fe/64 scope link + valid_lft forever preferred_lft forever + 8: docker0: mtu 1500 state DOWN + inet6 fe80::42:faff:fee6:40a0/64 scope link + valid_lft forever preferred_lft forever + 11: tun0: mtu 1500 state UNKNOWN qlen 100 + inet6 fe80::98a6:733e:dafd:350/64 scope link stable-privacy + valid_lft forever preferred_lft forever + 28: cni-podman0: mtu 1500 state DOWN qlen 1000 + inet6 fe80::3449:cbff:fe89:b87e/64 scope link + valid_lft forever preferred_lft forever + 31: vethaddb245@if30: mtu 1500 state UP + inet6 fe80::90f7:3eff:feed:a6bb/64 scope link + valid_lft forever preferred_lft forever + 33: veth88ba1e8@if32: mtu 1500 state UP + inet6 fe80::d:f5ff:fe73:8c82/64 scope link + valid_lft forever preferred_lft forever + 35: vethbd14d6b@if34: mtu 1500 state UP + inet6 fe80::b44f:8ff:fe6f:813d/64 scope link + valid_lft forever preferred_lft forever + 37: vethb6e5fc7@if36: mtu 1500 state UP + inet6 fe80::4869:c6ff:feaa:8afe/64 scope link + valid_lft forever preferred_lft forever + 39: veth13e8fd2@if38: mtu 1500 state UP + inet6 fe80::78f4:71ff:fefe:eb40/64 scope link + valid_lft forever preferred_lft forever + 41: veth1d3aa9e@if40: mtu 1500 state UP + inet6 fe80::24bd:88ff:fe28:5b18/64 scope link + valid_lft forever preferred_lft forever + 43: vethe485ca9@if42: mtu 1500 state UP + inet6 fe80::6425:87ff:fe42:b9f0/64 scope link + valid_lft forever preferred_lft forever + """), + { + "fe80::/64": { + "eno1": {"fe80::225:90ff:fee5:26e8"}, + "br-3d443496454c": {"fe80::42:23ff:fe9d:ee4"}, + "tun0": {"fe80::98a6:733e:dafd:350"}, + "br-4355f5dbb528": {"fe80::42:6eff:fe35:41fe"}, + "docker0": {"fe80::42:faff:fee6:40a0"}, + "cni-podman0": {"fe80::3449:cbff:fe89:b87e"}, + "veth88ba1e8": {"fe80::d:f5ff:fe73:8c82"}, + "vethb6e5fc7": {"fe80::4869:c6ff:feaa:8afe"}, + "vethaddb245": {"fe80::90f7:3eff:feed:a6bb"}, + "vethbd14d6b": {"fe80::b44f:8ff:fe6f:813d"}, + "veth13e8fd2": {"fe80::78f4:71ff:fefe:eb40"}, + "veth1d3aa9e": {"fe80::24bd:88ff:fe28:5b18"}, + "vethe485ca9": {"fe80::6425:87ff:fe42:b9f0"}, + } + } + ), + ( + dedent(""" + ::1 dev lo proto kernel metric 256 pref medium + 2001:1458:301:eb::100:1a dev ens20f0 proto kernel metric 100 pref medium + 2001:1458:301:eb::/64 dev ens20f0 proto ra metric 100 pref medium + fd01:1458:304:5e::/64 dev ens20f0 proto ra metric 100 pref medium + fe80::/64 dev ens20f0 proto kernel metric 100 pref medium + default proto ra metric 100 + nexthop via fe80::46ec:ce00:b8a0:d3c8 dev ens20f0 weight 1 + nexthop via fe80::46ec:ce00:b8a2:33c8 dev ens20f0 weight 1 pref medium + """), + dedent(""" + 1: lo: mtu 65536 state UNKNOWN qlen 1000 + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever + 2: ens20f0: mtu 1500 state UP qlen 1000 + inet6 2001:1458:301:eb::100:1a/128 scope global dynamic noprefixroute + valid_lft 590879sec preferred_lft 590879sec + inet6 fe80::2e60:cff:fef8:da41/64 scope link noprefixroute + valid_lft forever preferred_lft forever + inet6 fe80::2e60:cff:fef8:da41/64 scope link noprefixroute + valid_lft forever preferred_lft forever + inet6 fe80::2e60:cff:fef8:da41/64 scope link noprefixroute + valid_lft forever preferred_lft forever + """), + { + '2001:1458:301:eb::/64': { + 'ens20f0': { + '2001:1458:301:eb::100:1a' + }, + }, + 'fe80::/64': { + 'ens20f0': {'fe80::2e60:cff:fef8:da41'}, + }, + 'fd01:1458:304:5e::/64': { + 'ens20f0': set() + }, + } + ), + ]) + def test_parse_ipv6_route(self, test_routes, test_ips, expected): + assert cd._parse_ipv6_route(test_routes, test_ips) == expected + + @mock.patch.object(cd, 'call_throws', return_value=('10.4.0.1 dev tun0 proto kernel scope link src 10.4.0.2 metric 50\n', '', '')) + def test_command_list_networks(self, cephadm_fs, capsys): + with with_cephadm_ctx([]) as ctx: + cd.command_list_networks(ctx) + assert json.loads(capsys.readouterr().out) == { + '10.4.0.1': {'tun0': ['10.4.0.2']} + } \ No newline at end of file diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/api/lvm.py ceph-16.2.6/src/ceph-volume/ceph_volume/api/lvm.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/api/lvm.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/api/lvm.py 2021-09-16 14:27:19.000000000 +0000 @@ -463,7 +463,7 @@ :returns: list of class PVolume object representing pvs on the system """ filters = make_filters_lvmcmd_ready(filters, tags) - args = ['pvs', '--no-heading', '--readonly', '--separator=";"', '-S', + args = ['pvs', '--noheadings', '--readonly', '--separator=";"', '-S', filters, '-o', fields] stdout, stderr, returncode = process.call(args, verbose_on_failure=False) @@ -1134,3 +1134,15 @@ lvs = _output_parser(stdout, LV_FIELDS) return [Volume(**lv) for lv in lvs if lv['lv_name'] and lv['lv_name'].startswith(name_prefix)] + +def get_lv_by_fullname(full_name): + """ + returns LV by the specified LV's full name (formatted as vg_name/lv_name) + """ + try: + vg_name, lv_name = full_name.split('/') + res_lv = get_first_lv(filters={'lv_name': lv_name, + 'vg_name': vg_name}) + except ValueError: + res_lv = None + return res_lv diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/activate.py ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/activate.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/activate.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/activate.py 2021-09-16 14:27:19.000000000 +0000 @@ -269,6 +269,11 @@ tags = {'ceph.osd_id': osd_id, 'ceph.osd_fsid': osd_fsid} elif not osd_id and osd_fsid: tags = {'ceph.osd_fsid': osd_fsid} + elif osd_id and not osd_fsid: + raise RuntimeError('could not activate osd.{}, please provide the ' + 'osd_fsid too'.format(osd_id)) + else: + raise RuntimeError('Please provide both osd_id and osd_fsid') lvs = api.get_lvs(tags=tags) if not lvs: raise RuntimeError('could not find osd.%s with osd_fsid %s' % diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/batch.py ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/batch.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/batch.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/batch.py 2021-09-16 14:27:19.000000000 +0000 @@ -512,10 +512,11 @@ # fill up uneven distributions across fast devices: 5 osds and 2 fast # devices? create 3 slots on each device rather then deploying # heterogeneous osds - if (requested_osds - len(lvm_devs)) % len(phys_devs): - fast_slots_per_device = int((requested_osds - len(lvm_devs)) / len(phys_devs)) + 1 + slot_divider = max(1, len(phys_devs)) + if (requested_osds - len(lvm_devs)) % slot_divider: + fast_slots_per_device = int((requested_osds - len(lvm_devs)) / slot_divider) + 1 else: - fast_slots_per_device = int((requested_osds - len(lvm_devs)) / len(phys_devs)) + fast_slots_per_device = int((requested_osds - len(lvm_devs)) / slot_divider) ret.extend(get_physical_fast_allocs(phys_devs, diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/deactivate.py ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/deactivate.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/deactivate.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/deactivate.py 2021-09-16 14:27:19.000000000 +0000 @@ -54,8 +54,6 @@ ceph-volume lvm deactivate {ID} {FSID} - To deactivate all volumes use the --all flag. - ceph-volume lvm deactivate --all """) parser = argparse.ArgumentParser( prog='ceph-volume lvm deactivate', diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/main.py ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/main.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/main.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/main.py 2021-09-16 14:27:19.000000000 +0000 @@ -9,6 +9,7 @@ from . import listing from . import zap from . import batch +from . import migrate class LVM(object): @@ -30,6 +31,9 @@ 'trigger': trigger.Trigger, 'list': listing.List, 'zap': zap.Zap, + 'migrate': migrate.Migrate, + 'new-wal': migrate.NewWAL, + 'new-db': migrate.NewDB, } def __init__(self, argv): diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/migrate.py ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/migrate.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/devices/lvm/migrate.py 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/devices/lvm/migrate.py 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,690 @@ +from __future__ import print_function +import argparse +import logging +import os +from textwrap import dedent +from ceph_volume.util import system, disk, merge_dict +from ceph_volume.util.device import Device +from ceph_volume import decorators, terminal, process +from ceph_volume.api import lvm as api +from ceph_volume.systemd import systemctl + + +logger = logging.getLogger(__name__) +mlogger = terminal.MultiLogger(__name__) + +def get_cluster_name(osd_id, osd_fsid): + """ + From an ``osd_id`` and/or an ``osd_fsid``, filter out all the LVs in the + system that match those tag values, then return cluster_name for the first + one. + """ + lv_tags = {} + lv_tags['ceph.osd_id'] = osd_id + lv_tags['ceph.osd_fsid'] = osd_fsid + + lvs = api.get_lvs(tags=lv_tags) + if not lvs: + mlogger.error( + 'Unable to find any LV for source OSD: id:{} fsid:{}'.format( + osd_id, osd_fsid) ) + raise SystemExit('Unexpected error, terminating') + return next(iter(lvs)).tags["ceph.cluster_name"] + +def get_osd_path(osd_id, osd_fsid): + return '/var/lib/ceph/osd/{}-{}'.format( + get_cluster_name(osd_id, osd_fsid), osd_id) + +def find_associated_devices(osd_id, osd_fsid): + """ + From an ``osd_id`` and/or an ``osd_fsid``, filter out all the LVs in the + system that match those tag values, further detect if any partitions are + part of the OSD, and then return the set of LVs and partitions (if any). + """ + lv_tags = {} + lv_tags['ceph.osd_id'] = osd_id + lv_tags['ceph.osd_fsid'] = osd_fsid + + lvs = api.get_lvs(tags=lv_tags) + if not lvs: + mlogger.error( + 'Unable to find any LV for source OSD: id:{} fsid:{}'.format( + osd_id, osd_fsid) ) + raise SystemExit('Unexpected error, terminating') + + devices = set(ensure_associated_lvs(lvs, lv_tags)) + return [(Device(path), type) for path, type in devices if path] + +def ensure_associated_lvs(lvs, lv_tags): + """ + Go through each LV and ensure if backing devices (journal, wal, block) + are LVs or partitions, so that they can be accurately reported. + """ + # look for many LVs for each backing type, because it is possible to + # receive a filtering for osd.1, and have multiple failed deployments + # leaving many journals with osd.1 - usually, only a single LV will be + # returned + + block_lvs = api.get_lvs(tags=merge_dict(lv_tags, {'ceph.type': 'block'})) + db_lvs = api.get_lvs(tags=merge_dict(lv_tags, {'ceph.type': 'db'})) + wal_lvs = api.get_lvs(tags=merge_dict(lv_tags, {'ceph.type': 'wal'})) + backing_devices = [(block_lvs, 'block'), (db_lvs, 'db'), + (wal_lvs, 'wal')] + + verified_devices = [] + + for lv in lvs: + # go through each lv and append it, otherwise query `blkid` to find + # a physical device. Do this for each type (journal,db,wal) regardless + # if they have been processed in the previous LV, so that bad devices + # with the same ID can be caught + for ceph_lvs, type in backing_devices: + + if ceph_lvs: + verified_devices.extend([(l.lv_path, type) for l in ceph_lvs]) + continue + + # must be a disk partition, by querying blkid by the uuid we are + # ensuring that the device path is always correct + try: + device_uuid = lv.tags['ceph.{}_uuid'.format(type)] + except KeyError: + # Bluestore will not have ceph.journal_uuid, and Filestore + # will not not have ceph.db_uuid + continue + + osd_device = disk.get_device_from_partuuid(device_uuid) + if not osd_device: + # if the osd_device is not found by the partuuid, then it is + # not possible to ensure this device exists anymore, so skip it + continue + verified_devices.append((osd_device, type)) + + return verified_devices + +class VolumeTagTracker(object): + def __init__(self, devices, target_lv): + self.target_lv = target_lv + self.data_device = self.db_device = self.wal_device = None + for device, type in devices: + if type == 'block': + self.data_device = device + elif type == 'db': + self.db_device = device + elif type == 'wal': + self.wal_device = device + if not self.data_device: + mlogger.error('Data device not found') + raise SystemExit( + "Unexpected error, terminating") + if not self.data_device.is_lv: + mlogger.error('Data device isn\'t LVM') + raise SystemExit( + "Unexpected error, terminating") + + self.old_target_tags = self.target_lv.tags.copy() + self.old_data_tags = ( + self.data_device.lv_api.tags.copy() + if self.data_device.is_lv else None) + self.old_db_tags = ( + self.db_device.lv_api.tags.copy() + if self.db_device and self.db_device.is_lv else None) + self.old_wal_tags = ( + self.wal_device.lv_api.tags.copy() + if self.wal_device and self.wal_device.is_lv else None) + + def update_tags_when_lv_create(self, create_type): + tags = {} + if not self.data_device.is_lv: + mlogger.warning( + 'Data device is not LVM, wouldn\'t update LVM tags') + else: + tags["ceph.{}_uuid".format(create_type)] = self.target_lv.lv_uuid + tags["ceph.{}_device".format(create_type)] = self.target_lv.lv_path + self.data_device.lv_api.set_tags(tags) + + tags = self.data_device.lv_api.tags.copy() + tags["ceph.type"] = create_type + self.target_lv.set_tags(tags) + + aux_dev = None + if create_type == "db" and self.wal_device: + aux_dev = self.wal_device + elif create_type == "wal" and self.db_device: + aux_dev = self.db_device + else: + return + if not aux_dev.is_lv: + mlogger.warning( + '{} device is not LVM, wouldn\'t update LVM tags'.format( + create_type.upper())) + else: + tags = {} + tags["ceph.{}_uuid".format(create_type)] = self.target_lv.lv_uuid + tags["ceph.{}_device".format(create_type)] = self.target_lv.lv_path + aux_dev.lv_api.set_tags(tags) + + def remove_lvs(self, source_devices, target_type): + remaining_devices = [self.data_device, self.db_device, self.wal_device] + + outdated_tags = [] + for device, type in source_devices: + if type == "block" or type == target_type: + continue + remaining_devices.remove(device) + if device.is_lv: + outdated_tags.append("ceph.{}_uuid".format(type)) + outdated_tags.append("ceph.{}_device".format(type)) + device.lv_api.clear_tags() + if len(outdated_tags) > 0: + for d in remaining_devices: + if d and d.is_lv: + d.lv_api.clear_tags(outdated_tags) + + def replace_lvs(self, source_devices, target_type): + remaining_devices = [self.data_device] + if self.db_device: + remaining_devices.append(self.db_device) + if self.wal_device: + remaining_devices.append(self.wal_device) + + outdated_tags = [] + for device, type in source_devices: + if type == "block": + continue + remaining_devices.remove(device) + if device.is_lv: + outdated_tags.append("ceph.{}_uuid".format(type)) + outdated_tags.append("ceph.{}_device".format(type)) + device.lv_api.clear_tags() + + new_tags = {} + new_tags["ceph.{}_uuid".format(target_type)] = self.target_lv.lv_uuid + new_tags["ceph.{}_device".format(target_type)] = self.target_lv.lv_path + + for d in remaining_devices: + if d and d.is_lv: + if len(outdated_tags) > 0: + d.lv_api.clear_tags(outdated_tags) + d.lv_api.set_tags(new_tags) + + if not self.data_device.is_lv: + mlogger.warning( + 'Data device is not LVM, wouldn\'t properly update target LVM tags') + else: + tags = self.data_device.lv_api.tags.copy() + + tags["ceph.type"] = target_type + tags["ceph.{}_uuid".format(target_type)] = self.target_lv.lv_uuid + tags["ceph.{}_device".format(target_type)] = self.target_lv.lv_path + self.target_lv.set_tags(tags) + + def undo(self): + mlogger.info( + 'Undoing lv tag set') + if self.data_device: + if self.old_data_tags: + self.data_device.lv_api.set_tags(self.old_data_tags) + else: + self.data_device.lv_api.clear_tags() + if self.db_device: + if self.old_db_tags: + self.db_device.lv_api.set_tags(self.old_db_tags) + else: + self.db_device.lv_api.clear_tags() + if self.wal_device: + if self.old_wal_tags: + self.wal_device.lv_api.set_tags(self.old_wal_tags) + else: + self.wal_device.lv_api.clear_tags() + if self.old_target_tags: + self.target_lv.set_tags(self.old_target_tags) + else: + self.target_lv.clear_tags() + +class Migrate(object): + + help = 'Migrate BlueFS data from to another LVM device' + + def __init__(self, argv): + self.argv = argv + self.osd_id = None + + def get_source_devices(self, devices, target_type=""): + ret = [] + for device, type in devices: + if type == target_type: + continue + if type == 'block': + if 'data' not in self.args.from_: + continue; + elif type == 'db': + if 'db' not in self.args.from_: + continue; + elif type == 'wal': + if 'wal' not in self.args.from_: + continue; + ret.append([device, type]) + if ret == []: + mlogger.error('Source device list is empty') + raise SystemExit( + 'Unable to migrate to : {}'.format(self.args.target)) + return ret + + # ceph-bluestore-tool uses the following replacement rules + # (in the order of precedence, stop on the first match) + # if source list has DB volume - target device replaces it. + # if source list has WAL volume - target device replace it. + # if source list has slow volume only - operation isn’t permitted, + # requires explicit allocation via new-db/new-wal command.detects which + def get_target_type_by_source(self, devices): + ret = None + for device, type in devices: + if type == 'db': + return 'db' + elif type == 'wal': + ret = 'wal' + return ret + + def get_filename_by_type(self, type): + filename = 'block' + if type == 'db' or type == 'wal': + filename += '.' + type + return filename + + def get_source_args(self, osd_path, devices): + ret = [] + for device, type in devices: + ret = ret + ["--devs-source", os.path.join( + osd_path, self.get_filename_by_type(type))] + return ret + + @decorators.needs_root + def migrate_to_new(self, osd_id, osd_fsid, devices, target_lv): + source_devices = self.get_source_devices(devices) + target_type = self.get_target_type_by_source(source_devices) + if not target_type: + mlogger.error( + "Unable to determine new volume type," + " please use new-db or new-wal command before.") + raise SystemExit( + "Unable to migrate to : {}".format(self.args.target)) + + target_path = target_lv.lv_path + + try: + tag_tracker = VolumeTagTracker(devices, target_lv) + # we need to update lvm tags for all the remaining volumes + # and clear for ones which to be removed + + # ceph-bluestore-tool removes source volume(s) other than block one + # and attaches target one after successful migration + tag_tracker.replace_lvs(source_devices, target_type) + + osd_path = get_osd_path(osd_id, osd_fsid) + source_args = self.get_source_args(osd_path, source_devices) + mlogger.info("Migrate to new, Source: {} Target: {}".format( + source_args, target_path)) + stdout, stderr, exit_code = process.call([ + 'ceph-bluestore-tool', + '--path', + osd_path, + '--dev-target', + target_path, + '--command', + 'bluefs-bdev-migrate'] + + source_args) + if exit_code != 0: + mlogger.error( + 'Failed to migrate device, error code:{}'.format(exit_code)) + raise SystemExit( + 'Failed to migrate to : {}'.format(self.args.target)) + else: + system.chown(os.path.join(osd_path, "block.{}".format( + target_type))) + terminal.success('Migration successful.') + except: + tag_tracker.undo() + raise + + return + + @decorators.needs_root + def migrate_to_existing(self, osd_id, osd_fsid, devices, target_lv): + target_type = target_lv.tags["ceph.type"] + if target_type == "wal": + mlogger.error("Migrate to WAL is not supported") + raise SystemExit( + "Unable to migrate to : {}".format(self.args.target)) + target_filename = self.get_filename_by_type(target_type) + if (target_filename == ""): + mlogger.error( + "Target Logical Volume doesn't have proper volume type " + "(ceph.type LVM tag): {}".format(target_type)) + raise SystemExit( + "Unable to migrate to : {}".format(self.args.target)) + + osd_path = get_osd_path(osd_id, osd_fsid) + source_devices = self.get_source_devices(devices, target_type) + target_path = os.path.join(osd_path, target_filename) + tag_tracker = VolumeTagTracker(devices, target_lv) + + try: + # ceph-bluestore-tool removes source volume(s) other than + # block and target ones after successful migration + tag_tracker.remove_lvs(source_devices, target_type) + source_args = self.get_source_args(osd_path, source_devices) + mlogger.info("Migrate to existing, Source: {} Target: {}".format( + source_args, target_path)) + stdout, stderr, exit_code = process.call([ + 'ceph-bluestore-tool', + '--path', + osd_path, + '--dev-target', + target_path, + '--command', + 'bluefs-bdev-migrate'] + + source_args) + if exit_code != 0: + mlogger.error( + 'Failed to migrate device, error code:{}'.format(exit_code)) + raise SystemExit( + 'Failed to migrate to : {}'.format(self.args.target)) + else: + terminal.success('Migration successful.') + except: + tag_tracker.undo() + raise + + return + + @decorators.needs_root + def migrate_osd(self): + if self.args.osd_id and not self.args.no_systemd: + osd_is_running = systemctl.osd_is_active(self.args.osd_id) + if osd_is_running: + mlogger.error('OSD is running, stop it with: ' + 'systemctl stop ceph-osd@{}'.format( + self.args.osd_id)) + raise SystemExit( + 'Unable to migrate devices associated with OSD ID: {}' + .format(self.args.osd_id)) + + target_lv = api.get_lv_by_fullname(self.args.target) + if not target_lv: + mlogger.error( + 'Target path "{}" is not a Logical Volume'.formaat( + self.args.target)) + raise SystemExit( + 'Unable to migrate to : {}'.format(self.args.target)) + devices = find_associated_devices(self.args.osd_id, self.args.osd_fsid) + if (not target_lv.used_by_ceph): + self.migrate_to_new(self.args.osd_id, self.args.osd_fsid, + devices, + target_lv) + else: + if (target_lv.tags['ceph.osd_id'] != self.args.osd_id or + target_lv.tags['ceph.osd_fsid'] != self.args.osd_fsid): + mlogger.error( + 'Target Logical Volume isn\'t used by the specified OSD: ' + '{} FSID: {}'.format(self.args.osd_id, + self.args.osd_fsid)) + raise SystemExit( + 'Unable to migrate to : {}'.format(self.args.target)) + + self.migrate_to_existing(self.args.osd_id, self.args.osd_fsid, + devices, + target_lv) + + def make_parser(self, prog, sub_command_help): + parser = argparse.ArgumentParser( + prog=prog, + formatter_class=argparse.RawDescriptionHelpFormatter, + description=sub_command_help, + ) + + parser.add_argument( + '--osd-id', + required=True, + help='Specify an OSD ID to detect associated devices for zapping', + ) + + parser.add_argument( + '--osd-fsid', + required=True, + help='Specify an OSD FSID to detect associated devices for zapping', + ) + parser.add_argument( + '--target', + required=True, + help='Specify target Logical Volume (LV) to migrate data to', + ) + parser.add_argument( + '--from', + nargs='*', + dest='from_', + required=True, + choices=['data', 'db', 'wal'], + help='Copy BlueFS data from DB device', + ) + parser.add_argument( + '--no-systemd', + dest='no_systemd', + action='store_true', + help='Skip checking OSD systemd unit', + ) + return parser + + def main(self): + sub_command_help = dedent(""" + Moves BlueFS data from source volume(s) to the target one, source + volumes (except the main (i.e. data or block) one) are removed on + success. LVM volumes are permitted for Target only, both already + attached or new logical one. In the latter case it is attached to OSD + replacing one of the source devices. Following replacement rules apply + (in the order of precedence, stop on the first match): + * if source list has DB volume - target device replaces it. + * if source list has WAL volume - target device replace it. + * if source list has slow volume only - operation is not permitted, + requires explicit allocation via new-db/new-wal command. + + Example calls for supported scenarios: + + Moves BlueFS data from main device to LV already attached as DB: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data --target vgname/db + + Moves BlueFS data from shared main device to LV which will be attached + as a new DB: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data --target vgname/new_db + + Moves BlueFS data from DB device to new LV, DB is replaced: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from db --target vgname/new_db + + Moves BlueFS data from main and DB devices to new LV, DB is replaced: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data db --target vgname/new_db + + Moves BlueFS data from main, DB and WAL devices to new LV, WAL is + removed and DB is replaced: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data db wal --target vgname/new_db + + Moves BlueFS data from main, DB and WAL devices to main device, WAL + and DB are removed: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from db wal --target vgname/data + + """) + + parser = self.make_parser('ceph-volume lvm migrate', sub_command_help) + + if len(self.argv) == 0: + print(sub_command_help) + return + + self.args = parser.parse_args(self.argv) + + self.migrate_osd() + +class NewVolume(object): + def __init__(self, create_type, argv): + self.create_type = create_type + self.argv = argv + + def make_parser(self, prog, sub_command_help): + parser = argparse.ArgumentParser( + prog=prog, + formatter_class=argparse.RawDescriptionHelpFormatter, + description=sub_command_help, + ) + + parser.add_argument( + '--osd-id', + required=True, + help='Specify an OSD ID to attach new volume to', + ) + + parser.add_argument( + '--osd-fsid', + required=True, + help='Specify an OSD FSIDto attach new volume to', + ) + parser.add_argument( + '--target', + required=True, + help='Specify target Logical Volume (LV) to attach', + ) + parser.add_argument( + '--no-systemd', + dest='no_systemd', + action='store_true', + help='Skip checking OSD systemd unit', + ) + return parser + + @decorators.needs_root + def make_new_volume(self, osd_id, osd_fsid, devices, target_lv): + osd_path = get_osd_path(osd_id, osd_fsid) + mlogger.info( + 'Making new volume at {} for OSD: {} ({})'.format( + target_lv.lv_path, osd_id, osd_path)) + tag_tracker = VolumeTagTracker(devices, target_lv) + + try: + tag_tracker.update_tags_when_lv_create(self.create_type) + + stdout, stderr, exit_code = process.call([ + 'ceph-bluestore-tool', + '--path', + osd_path, + '--dev-target', + target_lv.lv_path, + '--command', + 'bluefs-bdev-new-{}'.format(self.create_type) + ]) + if exit_code != 0: + mlogger.error( + 'failed to attach new volume, error code:{}'.format( + exit_code)) + raise SystemExit( + "Failed to attach new volume: {}".format( + self.args.target)) + else: + system.chown(os.path.join(osd_path, "block.{}".format( + self.create_type))) + terminal.success('New volume attached.') + except: + tag_tracker.undo() + raise + return + + @decorators.needs_root + def new_volume(self): + if self.args.osd_id and not self.args.no_systemd: + osd_is_running = systemctl.osd_is_active(self.args.osd_id) + if osd_is_running: + mlogger.error('OSD ID is running, stop it with:' + ' systemctl stop ceph-osd@{}'.format(self.args.osd_id)) + raise SystemExit( + 'Unable to attach new volume for OSD: {}'.format( + self.args.osd_id)) + + target_lv = api.get_lv_by_fullname(self.args.target) + if not target_lv: + mlogger.error( + 'Target path {} is not a Logical Volume'.format( + self.args.target)) + raise SystemExit( + 'Unable to attach new volume : {}'.format(self.args.target)) + if target_lv.used_by_ceph: + mlogger.error( + 'Target Logical Volume is already used by ceph: {}'.format( + self.args.target)) + raise SystemExit( + 'Unable to attach new volume : {}'.format(self.args.target)) + else: + devices = find_associated_devices(self.args.osd_id, + self.args.osd_fsid) + self.make_new_volume( + self.args.osd_id, + self.args.osd_fsid, + devices, + target_lv) + +class NewWAL(NewVolume): + + help = 'Allocate new WAL volume for OSD at specified Logical Volume' + + def __init__(self, argv): + super(NewWAL, self).__init__("wal", argv) + + def main(self): + sub_command_help = dedent(""" + Attaches the given logical volume to the given OSD as a WAL volume. + Logical volume format is vg/lv. Fails if OSD has already got attached DB. + + Example: + + Attach vgname/lvname as a WAL volume to OSD 1 + + ceph-volume lvm new-wal --osd-id 1 --osd-fsid 55BD4219-16A7-4037-BC20-0F158EFCC83D --target vgname/new_wal + """) + parser = self.make_parser('ceph-volume lvm new-wal', sub_command_help) + + if len(self.argv) == 0: + print(sub_command_help) + return + + self.args = parser.parse_args(self.argv) + + self.new_volume() + +class NewDB(NewVolume): + + help = 'Allocate new DB volume for OSD at specified Logical Volume' + + def __init__(self, argv): + super(NewDB, self).__init__("db", argv) + + def main(self): + sub_command_help = dedent(""" + Attaches the given logical volume to the given OSD as a DB volume. + Logical volume format is vg/lv. Fails if OSD has already got attached DB. + + Example: + + Attach vgname/lvname as a DB volume to OSD 1 + + ceph-volume lvm new-db --osd-id 1 --osd-fsid 55BD4219-16A7-4037-BC20-0F158EFCC83D --target vgname/new_db + """) + + parser = self.make_parser('ceph-volume lvm new-db', sub_command_help) + if len(self.argv) == 0: + print(sub_command_help) + return + self.args = parser.parse_args(self.argv) + + self.new_volume() diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/devices/raw/list.py ceph-16.2.6/src/ceph-volume/ceph_volume/devices/raw/list.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/devices/raw/list.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/devices/raw/list.py 2021-09-16 14:27:19.000000000 +0000 @@ -4,10 +4,12 @@ import logging from textwrap import dedent from ceph_volume import decorators, process +from ceph_volume.util import disk logger = logging.getLogger(__name__) + def direct_report(devices): """ Other non-cli consumers of listing information will want to consume the @@ -18,6 +20,40 @@ _list = List([]) return _list.generate(devices) +def _get_bluestore_info(dev): + out, err, rc = process.call([ + 'ceph-bluestore-tool', 'show-label', + '--dev', dev], verbose_on_failure=False) + if rc: + # ceph-bluestore-tool returns an error (below) if device is not bluestore OSD + # > unable to read label for : (2) No such file or directory + # but it's possible the error could be for a different reason (like if the disk fails) + logger.debug('assuming device {} is not BlueStore; ceph-bluestore-tool failed to get info from device: {}\n{}'.format(dev, out, err)) + return None + oj = json.loads(''.join(out)) + if dev not in oj: + # should be impossible, so warn + logger.warning('skipping device {} because it is not reported in ceph-bluestore-tool output: {}'.format(dev, out)) + return None + try: + if oj[dev]['description'] != 'main': + # ignore non-main devices, for now + logger.info('ignoring non-main device {}'.format(dev)) + return None + whoami = oj[dev]['whoami'] + return { + 'type': 'bluestore', + 'osd_id': int(whoami), + 'osd_uuid': oj[dev]['osd_uuid'], + 'ceph_fsid': oj[dev]['ceph_fsid'], + 'device': dev + } + except KeyError as e: + # this will appear for devices that have a bluestore header but aren't valid OSDs + # for example, due to incomplete rollback of OSDs: https://tracker.ceph.com/issues/51869 + logger.error('device {} does not have all BlueStore data needed to be a valid OSD: {}\n{}'.format(dev, out, e)) + return None + class List(object): @@ -27,64 +63,53 @@ self.argv = argv def generate(self, devs=None): - if not devs: - logger.debug('Listing block devices via lsblk...') + logger.debug('Listing block devices via lsblk...') + + if devs is None or devs == []: devs = [] - # adding '--inverse' allows us to get the mapper devices list in that command output. - # not listing root devices containing partitions shouldn't have side effect since we are - # in `ceph-volume raw` context. - # - # example: - # running `lsblk --paths --nodeps --output=NAME --noheadings` doesn't allow to get the mapper list - # because the output is like following : - # - # $ lsblk --paths --nodeps --output=NAME --noheadings - # /dev/sda - # /dev/sdb - # /dev/sdc - # /dev/sdd - # - # the dmcrypt mappers are hidden because of the `--nodeps` given they are displayed as a dependency. - # - # $ lsblk --paths --output=NAME --noheadings - # /dev/sda - # |-/dev/mapper/ceph-3b52c90d-6548-407d-bde1-efd31809702f-sda-block-dmcrypt - # `-/dev/mapper/ceph-3b52c90d-6548-407d-bde1-efd31809702f-sda-db-dmcrypt - # /dev/sdb - # /dev/sdc - # /dev/sdd - # - # adding `--inverse` is a trick to get around this issue, the counterpart is that we can't list root devices if they contain - # at least one partition but this shouldn't be an issue in `ceph-volume raw` context given we only deal with raw devices. + # If no devs are given initially, we want to list ALL devices including children and + # parents. Parent disks with child partitions may be the appropriate device to return if + # the parent disk has a bluestore header, but children may be the most appropriate + # devices to return if the parent disk does not have a bluestore header. out, err, ret = process.call([ - 'lsblk', '--paths', '--nodeps', '--output=NAME', '--noheadings', '--inverse' + 'lsblk', '--paths', '--output=NAME', '--noheadings', '--list' ]) assert not ret devs = out + result = {} + logger.debug('inspecting devices: {}'.format(devs)) for dev in devs: - logger.debug('Examining %s' % dev) - # bluestore? - out, err, ret = process.call([ - 'ceph-bluestore-tool', 'show-label', - '--dev', dev], verbose_on_failure=False) - if ret: - logger.debug('No label on %s' % dev) - continue - oj = json.loads(''.join(out)) - if dev not in oj: + info = disk.lsblk(dev, abspath=True) + # Linux kernels built with CONFIG_ATARI_PARTITION enabled can falsely interpret + # bluestore's on-disk format as an Atari partition table. These false Atari partitions + # can be interpreted as real OSDs if a bluestore OSD was previously created on the false + # partition. See https://tracker.ceph.com/issues/52060 for more info. If a device has a + # parent, it is a child. If the parent is a valid bluestore OSD, the child will only + # exist if it is a phantom Atari partition, and the child should be ignored. If the + # parent isn't bluestore, then the child could be a valid bluestore OSD. If we fail to + # determine whether a parent is bluestore, we should err on the side of not reporting + # the child so as not to give a false negative. + if 'PKNAME' in info and info['PKNAME'] != "": + parent = info['PKNAME'] + try: + if disk.has_bluestore_label(parent): + logger.warning(('ignoring child device {} whose parent {} is a BlueStore OSD.'.format(dev, parent), + 'device is likely a phantom Atari partition. device info: {}'.format(info))) + continue + except OSError as e: + logger.error(('ignoring child device {} to avoid reporting invalid BlueStore data from phantom Atari partitions.'.format(dev), + 'failed to determine if parent device {} is BlueStore. err: {}'.format(parent, e))) + continue + + bs_info = _get_bluestore_info(dev) + if bs_info is None: + # None is also returned in the rare event that there is an issue reading info from + # a BlueStore disk, so be sure to log our assumption that it isn't bluestore + logger.info('device {} does not have BlueStore information'.format(dev)) continue - if oj[dev]['description'] != 'main': - # ignore non-main devices, for now - continue - whoami = oj[dev]['whoami'] - result[oj[dev]['osd_uuid']] = { - 'type': 'bluestore', - 'osd_id': int(whoami), - 'osd_uuid': oj[dev]['osd_uuid'], - 'ceph_fsid': oj[dev]['ceph_fsid'], - 'device': dev - } + result[bs_info['osd_uuid']] = bs_info + return result @decorators.needs_root diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/conftest.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/conftest.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/conftest.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/conftest.py 2021-09-16 14:27:19.000000000 +0000 @@ -52,6 +52,8 @@ dev.used_by_ceph = False dev.vg_size = [size] dev.vg_free = dev.vg_size + dev.available_lvm = True + dev.is_device = False dev.lvs = [lvm.Volume(vg_name=dev.vg_name, lv_name=dev.lv_name, lv_size=size, lv_tags='')] return dev return mock_lv diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/lvm/test_activate.py 2021-09-16 14:27:19.000000000 +0000 @@ -58,6 +58,18 @@ with pytest.raises(RuntimeError): activate.Activate([]).activate(args) + def test_osd_id_no_osd_fsid(self, is_root): + args = Args(osd_id=42, osd_fsid=None) + with pytest.raises(RuntimeError) as result: + activate.Activate([]).activate(args) + assert result.value.args[0] == 'could not activate osd.42, please provide the osd_fsid too' + + def test_no_osd_id_no_osd_fsid(self, is_root): + args = Args(osd_id=None, osd_fsid=None) + with pytest.raises(RuntimeError) as result: + activate.Activate([]).activate(args) + assert result.value.args[0] == 'Please provide both osd_id and osd_fsid' + def test_filestore_no_systemd(self, is_root, monkeypatch, capture): monkeypatch.setattr('ceph_volume.configuration.load', lambda: None) fake_enable = Capture() diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/lvm/test_batch.py 2021-09-16 14:27:19.000000000 +0000 @@ -209,6 +209,15 @@ 'block_db', 2, 2, args) assert len(fast) == 2 + def test_batch_fast_allocations_one_block_db_length(self, factory, conf_ceph_stub, + mock_lv_device_generator): + conf_ceph_stub('[global]\nfsid=asdf-lkjh') + + b = batch.Batch([]) + db_lv_devices = [mock_lv_device_generator()] + fast = b.fast_allocations(db_lv_devices, 1, 0, 'block_db') + assert len(fast) == 1 + @pytest.mark.parametrize('occupied_prior', range(7)) @pytest.mark.parametrize('slots,num_devs', [l for sub in [list(zip([x]*x, range(1, x + 1))) for x in range(1,7)] for l in sub]) diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/lvm/test_migrate.py 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,2295 @@ +import pytest +from mock.mock import patch +from ceph_volume import process +from ceph_volume.api import lvm as api +from ceph_volume.devices.lvm import migrate +from ceph_volume.util.device import Device +from ceph_volume.util import system + +class TestGetClusterName(object): + + mock_volumes = [] + def mock_get_lvs(self, *args, **kwargs): + return self.mock_volumes.pop(0) + + def test_cluster_found(self, monkeypatch): + tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data,ceph.osd_fsid=1234,ceph.cluster_name=name_of_the_cluster' + vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='', + lv_path='/dev/VolGroup/lv1', lv_tags=tags) + self.mock_volumes = [] + self.mock_volumes.append([vol]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + monkeypatch.setattr(process, 'call', lambda x, **kw: ('', '', 0)) + + result = migrate.get_cluster_name(osd_id='0', osd_fsid='1234') + assert "name_of_the_cluster" == result + + def test_cluster_not_found(self, monkeypatch, capsys): + self.mock_volumes = [] + self.mock_volumes.append([]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + monkeypatch.setattr(process, 'call', lambda x, **kw: ('', '', 0)) + + with pytest.raises(SystemExit) as error: + migrate.get_cluster_name(osd_id='0', osd_fsid='1234') + stdout, stderr = capsys.readouterr() + expected = 'Unexpected error, terminating' + assert expected in str(error.value) + expected = 'Unable to find any LV for source OSD: id:0 fsid:1234' + assert expected in stderr + +class TestFindAssociatedDevices(object): + + mock_volumes = [] + def mock_get_lvs(self, *args, **kwargs): + return self.mock_volumes.pop(0) + + mock_single_volumes = {} + def mock_get_first_lv(self, *args, **kwargs): + p = kwargs['filters']['lv_path'] + return self.mock_single_volumes[p] + + def test_lv_is_matched_id(self, monkeypatch): + tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data,ceph.osd_fsid=1234' + vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='', + lv_path='/dev/VolGroup/lv1', lv_tags=tags) + self.mock_volumes = [] + self.mock_volumes.append([vol]) + self.mock_volumes.append([vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([]) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': vol} + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + monkeypatch.setattr(process, 'call', lambda x, **kw: ('', '', 0)) + + result = migrate.find_associated_devices(osd_id='0', osd_fsid='1234') + assert len(result) == 1 + assert result[0][0].abspath == '/dev/VolGroup/lv1' + assert result[0][0].lvs == [vol] + assert result[0][1] == 'block' + + def test_lv_is_matched_id2(self, monkeypatch): + tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data,ceph.osd_fsid=1234' + vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=tags) + tags2 = 'ceph.osd_id=0,ceph.journal_uuid=xx,ceph.type=wal,ceph.osd_fsid=1234' + vol2 = api.Volume(lv_name='volume2', lv_uuid='z', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=tags2) + self.mock_volumes = [] + self.mock_volumes.append([vol]) + self.mock_volumes.append([vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([vol2]) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': vol, '/dev/VolGroup/lv2': vol2} + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + monkeypatch.setattr(process, 'call', lambda x, **kw: ('', '', 0)) + + result = migrate.find_associated_devices(osd_id='0', osd_fsid='1234') + assert len(result) == 2 + for d in result: + if d[1] == 'block': + assert d[0].abspath == '/dev/VolGroup/lv1' + assert d[0].lvs == [vol] + elif d[1] == 'wal': + assert d[0].abspath == '/dev/VolGroup/lv2' + assert d[0].lvs == [vol2] + else: + assert False + + def test_lv_is_matched_id3(self, monkeypatch): + tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data,ceph.osd_fsid=1234' + vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=tags) + tags2 = 'ceph.osd_id=0,ceph.journal_uuid=xx,ceph.type=wal,ceph.osd_fsid=1234' + vol2 = api.Volume(lv_name='volume2', lv_uuid='z', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=tags2) + tags3 = 'ceph.osd_id=0,ceph.journal_uuid=xx,ceph.type=db,ceph.osd_fsid=1234' + vol3 = api.Volume(lv_name='volume3', lv_uuid='z', vg_name='vg', + lv_path='/dev/VolGroup/lv3', lv_tags=tags3) + + self.mock_volumes = [] + self.mock_volumes.append([vol]) + self.mock_volumes.append([vol]) + self.mock_volumes.append([vol3]) + self.mock_volumes.append([vol2]) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': vol, + '/dev/VolGroup/lv2': vol2, + '/dev/VolGroup/lv3': vol3} + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + monkeypatch.setattr(process, 'call', lambda x, **kw: ('', '', 0)) + + result = migrate.find_associated_devices(osd_id='0', osd_fsid='1234') + assert len(result) == 3 + for d in result: + if d[1] == 'block': + assert d[0].abspath == '/dev/VolGroup/lv1' + assert d[0].lvs == [vol] + elif d[1] == 'wal': + assert d[0].abspath == '/dev/VolGroup/lv2' + assert d[0].lvs == [vol2] + elif d[1] == 'db': + assert d[0].abspath == '/dev/VolGroup/lv3' + assert d[0].lvs == [vol3] + else: + assert False + + def test_lv_is_not_matched(self, monkeypatch, capsys): + self.mock_volumes = [None] + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + monkeypatch.setattr(process, 'call', lambda x, **kw: ('', '', 0)) + + with pytest.raises(SystemExit) as error: + migrate.find_associated_devices(osd_id='1', osd_fsid='1234') + stdout, stderr = capsys.readouterr() + expected = 'Unexpected error, terminating' + assert expected in str(error.value) + expected = 'Unable to find any LV for source OSD: id:1 fsid:1234' + assert expected in stderr + +class TestVolumeTagTracker(object): + mock_single_volumes = {} + def mock_get_first_lv(self, *args, **kwargs): + p = kwargs['filters']['lv_path'] + return self.mock_single_volumes[p] + + mock_process_input = [] + def mock_process(self, *args, **kwargs): + self.mock_process_input.append(args[0]); + return ('', '', 0) + + def test_init(self, monkeypatch): + source_tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data,ceph.osd_fsid=1234' + source_db_tags = 'ceph.osd_id=0,journal_uuid=x,ceph.type=db, osd_fsid=1234' + source_wal_tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=wal' + target_tags="ceph.a=1,ceph.b=2,c=3,ceph.d=4" # 'c' to be bypassed + devices=[] + + data_vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=source_db_tags) + wal_vol = api.Volume(lv_name='volume3', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv3', lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol} + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + data_device = Device(path = '/dev/VolGroup/lv1') + db_device = Device(path = '/dev/VolGroup/lv2') + wal_device = Device(path = '/dev/VolGroup/lv3') + devices.append([data_device, 'block']) + devices.append([db_device, 'db']) + devices.append([wal_device, 'wal']) + + target = api.Volume(lv_name='target_name', lv_tags=target_tags, + lv_path='/dev/VolGroup/lv_target') + t = migrate.VolumeTagTracker(devices, target); + + assert 3 == len(t.old_target_tags) + + assert data_device == t.data_device + assert 4 == len(t.old_data_tags) + assert 'data' == t.old_data_tags['ceph.type'] + + assert db_device == t.db_device + assert 2 == len(t.old_db_tags) + assert 'db' == t.old_db_tags['ceph.type'] + + assert wal_device == t.wal_device + assert 3 == len(t.old_wal_tags) + assert 'wal' == t.old_wal_tags['ceph.type'] + + def test_update_tags_when_lv_create(self, monkeypatch): + source_tags = \ + 'ceph.osd_id=0,ceph.journal_uuid=x,' \ + 'ceph.type=data,ceph.osd_fsid=1234' + source_db_tags = \ + 'ceph.osd_id=0,journal_uuid=x,ceph.type=db,' \ + 'osd_fsid=1234' + + devices=[] + + data_vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=source_db_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + data_device = Device(path = '/dev/VolGroup/lv1') + db_device = Device(path = '/dev/VolGroup/lv2') + devices.append([data_device, 'block']) + devices.append([db_device, 'db']) + + target = api.Volume(lv_name='target_name', lv_tags='', + lv_uuid='wal_uuid', + lv_path='/dev/VolGroup/lv_target') + t = migrate.VolumeTagTracker(devices, target); + + self.mock_process_input = [] + t.update_tags_when_lv_create('wal') + + assert 3 == len(self.mock_process_input) + + assert ['lvchange', + '--addtag', 'ceph.wal_uuid=wal_uuid', + '--addtag', 'ceph.wal_device=/dev/VolGroup/lv_target', + '/dev/VolGroup/lv1'] == self.mock_process_input[0] + + assert self.mock_process_input[1].sort() == [ + 'lvchange', + '--addtag', 'ceph.osd_id=0', + '--addtag', 'ceph.journal_uuid=x', + '--addtag', 'ceph.type=wal', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.wal_uuid=wal_uuid', + '--addtag', 'ceph.wal_device=/dev/VolGroup/lv_target', + '/dev/VolGroup/lv_target'].sort() + + assert ['lvchange', + '--addtag', 'ceph.wal_uuid=wal_uuid', + '--addtag', 'ceph.wal_device=/dev/VolGroup/lv_target', + '/dev/VolGroup/lv2'] == self.mock_process_input[2] + + def test_remove_lvs(self, monkeypatch): + source_tags = \ + 'ceph.osd_id=0,ceph.journal_uuid=x,' \ + 'ceph.type=data,ceph.osd_fsid=1234,ceph.wal_uuid=aaaaa' + source_db_tags = \ + 'ceph.osd_id=0,journal_uuid=x,ceph.type=db,' \ + 'osd_fsid=1234,ceph.wal_device=aaaaa' + source_wal_tags = \ + 'ceph.wal_uuid=uuid,ceph.wal_device=device,' \ + 'ceph.osd_id=0,ceph.type=wal' + + devices=[] + + data_vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=source_db_tags) + wal_vol = api.Volume(lv_name='volume3', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv3', lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + data_device = Device(path = '/dev/VolGroup/lv1') + db_device = Device(path = '/dev/VolGroup/lv2') + wal_device = Device(path = '/dev/VolGroup/lv3') + devices.append([data_device, 'block']) + devices.append([db_device, 'db']) + devices.append([wal_device, 'wal']) + + target = api.Volume(lv_name='target_name', lv_tags='', + lv_path='/dev/VolGroup/lv_target') + t = migrate.VolumeTagTracker(devices, target); + + device_to_remove = devices.copy() + + self.mock_process_input = [] + t.remove_lvs(device_to_remove, 'db') + + assert 3 == len(self.mock_process_input) + assert ['lvchange', + '--deltag', 'ceph.wal_uuid=uuid', + '--deltag', 'ceph.wal_device=device', + '--deltag', 'ceph.osd_id=0', + '--deltag', 'ceph.type=wal', + '/dev/VolGroup/lv3'] == self.mock_process_input[0] + assert ['lvchange', + '--deltag', 'ceph.wal_uuid=aaaaa', + '/dev/VolGroup/lv1'] == self.mock_process_input[1] + assert ['lvchange', + '--deltag', 'ceph.wal_device=aaaaa', + '/dev/VolGroup/lv2'] == self.mock_process_input[2] + + def test_replace_lvs(self, monkeypatch): + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234,'\ + 'ceph.wal_uuid=wal_uuid,ceph.db_device=/dbdevice' + source_db_tags = \ + 'ceph.osd_id=0,ceph.type=db,ceph.osd_fsid=1234' + source_wal_tags = \ + 'ceph.wal_uuid=uuid,ceph.wal_device=device,' \ + 'ceph.osd_id=0,ceph.type=wal' + + devices=[] + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', lv_uuid='dbuuid', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=source_db_tags) + wal_vol = api.Volume(lv_name='volume3', lv_uuid='waluuid', vg_name='vg', + lv_path='/dev/VolGroup/lv3', lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + data_device = Device(path = '/dev/VolGroup/lv1') + db_device = Device(path = '/dev/VolGroup/lv2') + wal_device = Device(path = '/dev/VolGroup/lv3') + devices.append([data_device, 'block']) + devices.append([db_device, 'db']) + devices.append([wal_device, 'wal']) + + target = api.Volume(lv_name='target_name', + lv_uuid='ttt', + lv_tags='ceph.tag_to_remove=aaa', + lv_path='/dev/VolGroup/lv_target') + t = migrate.VolumeTagTracker(devices, target); + + self.mock_process_input = [] + t.replace_lvs(devices, 'db') + + assert 5 == len(self.mock_process_input) + + assert ['lvchange', + '--deltag', 'ceph.osd_id=0', + '--deltag', 'ceph.type=db', + '--deltag', 'ceph.osd_fsid=1234', + '/dev/VolGroup/lv2'] == self.mock_process_input[0] + assert ['lvchange', + '--deltag', 'ceph.wal_uuid=uuid', + '--deltag', 'ceph.wal_device=device', + '--deltag', 'ceph.osd_id=0', + '--deltag', 'ceph.type=wal', + '/dev/VolGroup/lv3'] == self.mock_process_input[1] + assert ['lvchange', + '--deltag', 'ceph.db_device=/dbdevice', + '--deltag', 'ceph.wal_uuid=wal_uuid', + '/dev/VolGroup/lv1'] == self.mock_process_input[2] + + assert ['lvchange', + '--addtag', 'ceph.db_uuid=ttt', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv_target', + '/dev/VolGroup/lv1'] == self.mock_process_input[3] + + assert self.mock_process_input[4].sort() == [ + 'lvchange', + '--addtag', 'ceph.osd_id=0', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.db_uuid=ttt', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv_target', + '/dev/VolGroup/lv_target'].sort() + + def test_undo(self, monkeypatch): + source_tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=data,ceph.osd_fsid=1234' + source_db_tags = 'ceph.osd_id=0,journal_uuid=x,ceph.type=db, osd_fsid=1234' + source_wal_tags = 'ceph.osd_id=0,ceph.journal_uuid=x,ceph.type=wal' + target_tags="" + devices=[] + + data_vol = api.Volume(lv_name='volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv2', lv_tags=source_db_tags) + wal_vol = api.Volume(lv_name='volume3', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/lv3', lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + data_device = Device(path = '/dev/VolGroup/lv1') + db_device = Device(path = '/dev/VolGroup/lv2') + wal_device = Device(path = '/dev/VolGroup/lv3') + devices.append([data_device, 'block']) + devices.append([db_device, 'db']) + devices.append([wal_device, 'wal']) + + target = api.Volume(lv_name='target_name', lv_tags=target_tags, + lv_path='/dev/VolGroup/lv_target') + t = migrate.VolumeTagTracker(devices, target); + + target.tags['ceph.a'] = 'aa'; + target.tags['ceph.b'] = 'bb'; + + data_vol.tags['ceph.journal_uuid'] = 'z'; + + db_vol.tags.pop('ceph.type') + + wal_vol.tags.clear() + + assert 2 == len(target.tags) + assert 4 == len(data_vol.tags) + assert 1 == len(db_vol.tags) + + self.mock_process_input = [] + t.undo() + + assert 0 == len(target.tags) + assert 4 == len(data_vol.tags) + assert 'x' == data_vol.tags['ceph.journal_uuid'] + + assert 2 == len(db_vol.tags) + assert 'db' == db_vol.tags['ceph.type'] + + assert 3 == len(wal_vol.tags) + assert 'wal' == wal_vol.tags['ceph.type'] + + assert 6 == len(self.mock_process_input) + assert 'lvchange' in self.mock_process_input[0] + assert '--deltag' in self.mock_process_input[0] + assert 'ceph.journal_uuid=z' in self.mock_process_input[0] + assert '/dev/VolGroup/lv1' in self.mock_process_input[0] + + assert 'lvchange' in self.mock_process_input[1] + assert '--addtag' in self.mock_process_input[1] + assert 'ceph.journal_uuid=x' in self.mock_process_input[1] + assert '/dev/VolGroup/lv1' in self.mock_process_input[1] + + assert 'lvchange' in self.mock_process_input[2] + assert '--deltag' in self.mock_process_input[2] + assert 'ceph.osd_id=0' in self.mock_process_input[2] + assert '/dev/VolGroup/lv2' in self.mock_process_input[2] + + assert 'lvchange' in self.mock_process_input[3] + assert '--addtag' in self.mock_process_input[3] + assert 'ceph.type=db' in self.mock_process_input[3] + assert '/dev/VolGroup/lv2' in self.mock_process_input[3] + + assert 'lvchange' in self.mock_process_input[4] + assert '--addtag' in self.mock_process_input[4] + assert 'ceph.type=wal' in self.mock_process_input[4] + assert '/dev/VolGroup/lv3' in self.mock_process_input[4] + + assert 'lvchange' in self.mock_process_input[5] + assert '--deltag' in self.mock_process_input[5] + assert 'ceph.a=aa' in self.mock_process_input[5] + assert 'ceph.b=bb' in self.mock_process_input[5] + assert '/dev/VolGroup/lv_target' in self.mock_process_input[5] + +class TestNew(object): + + mock_volume = None + def mock_get_lv_by_fullname(self, *args, **kwargs): + return self.mock_volume + + mock_process_input = [] + def mock_process(self, *args, **kwargs): + self.mock_process_input.append(args[0]); + return ('', '', 0) + + mock_single_volumes = {} + def mock_get_first_lv(self, *args, **kwargs): + p = kwargs['filters']['lv_path'] + return self.mock_single_volumes[p] + + mock_volumes = [] + def mock_get_lvs(self, *args, **kwargs): + return self.mock_volumes.pop(0) + + def test_newdb_non_root(self): + with pytest.raises(Exception) as error: + migrate.NewDB(argv=[ + '--osd-id', '1', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_db']).main() + expected = 'This command needs to be executed with sudo or as root' + assert expected in str(error.value) + + @patch('os.getuid') + def test_newdb_not_target_lvm(self, m_getuid, capsys): + m_getuid.return_value = 0 + with pytest.raises(SystemExit) as error: + migrate.NewDB(argv=[ + '--osd-id', '1', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_db']).main() + stdout, stderr = capsys.readouterr() + expected = 'Unable to attach new volume : vgname/new_db' + assert expected in str(error.value) + expected = 'Target path vgname/new_db is not a Logical Volume' + assert expected in stderr + + + @patch('os.getuid') + def test_newdb_already_in_use(self, m_getuid, monkeypatch, capsys): + m_getuid.return_value = 0 + + self.mock_volume = api.Volume(lv_name='volume1', + lv_uuid='y', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags='ceph.osd_id=5') # this results in set used_by_ceph + monkeypatch.setattr(api, 'get_lv_by_fullname', self.mock_get_lv_by_fullname) + + with pytest.raises(SystemExit) as error: + migrate.NewDB(argv=[ + '--osd-id', '1', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_db']).main() + stdout, stderr = capsys.readouterr() + expected = 'Unable to attach new volume : vgname/new_db' + assert expected in str(error.value) + expected = 'Target Logical Volume is already used by ceph: vgname/new_db' + assert expected in stderr + + @patch('os.getuid') + def test_newdb(self, m_getuid, monkeypatch, capsys): + m_getuid.return_value = 0 + + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234,'\ + 'ceph.wal_uuid=wal_uuid,ceph.db_device=/dbdevice' + source_wal_tags = \ + 'ceph.wal_uuid=uuid,ceph.wal_device=device,' \ + 'ceph.osd_id=0,ceph.type=wal' + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv3': wal_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + self.mock_volume = api.Volume(lv_name='target_volume1', lv_uuid='y', + vg_name='vg', + lv_path='/dev/VolGroup/target_volume', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + #find_associated_devices will call get_lvs() 4 times + # and it this needs results to be arranged that way + self.mock_volumes = [] + self.mock_volumes.append([data_vol, wal_vol]) + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([wal_vol]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph_cluster') + monkeypatch.setattr(system, 'chown', lambda path: 0) + + migrate.NewDB(argv=[ + '--osd-id', '1', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_db']).main() + + n = len(self.mock_process_input) + assert n >= 5 + + assert self.mock_process_input[n - 5] == [ + 'lvchange', + '--deltag', 'ceph.db_device=/dbdevice', + '/dev/VolGroup/lv1'] + assert self.mock_process_input[n - 4] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=y', + '--addtag', 'ceph.db_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/lv1'] + + assert self.mock_process_input[n - 3].sort() == [ + 'lvchange', + '--addtag', 'ceph.wal_uuid=uuid', + '--addtag', 'ceph.osd_id=0', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.db_uuid=y', + '--addtag', 'ceph.db_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/target_volume'].sort() + + assert self.mock_process_input[n - 2] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=y', + '--addtag', 'ceph.db_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/lv3'] + + assert self.mock_process_input[n - 1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph_cluster-1', + '--dev-target', '/dev/VolGroup/target_volume', + '--command', 'bluefs-bdev-new-db'] + + def test_newdb_active_systemd(self, is_root, monkeypatch, capsys): + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234,'\ + 'ceph.wal_uuid=wal_uuid,ceph.db_device=/dbdevice' + source_wal_tags = \ + 'ceph.wal_uuid=uuid,ceph.wal_device=device,' \ + 'ceph.osd_id=0,ceph.type=wal' + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv3': wal_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + self.mock_volume = api.Volume(lv_name='target_volume1', lv_uuid='y', + vg_name='vg', + lv_path='/dev/VolGroup/target_volume', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: True) + + #find_associated_devices will call get_lvs() 4 times + # and it this needs results to be arranged that way + self.mock_volumes = [] + self.mock_volumes.append([data_vol, wal_vol]) + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([wal_vol]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph_cluster') + monkeypatch.setattr(system, 'chown', lambda path: 0) + + m = migrate.NewDB(argv=[ + '--osd-id', '1', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_db']) + + with pytest.raises(SystemExit) as error: + m.main() + + stdout, stderr = capsys.readouterr() + + assert 'Unable to attach new volume for OSD: 1' == str(error.value) + assert '--> OSD ID is running, stop it with: systemctl stop ceph-osd@1' == stderr.rstrip() + assert not stdout + + def test_newdb_no_systemd(self, is_root, monkeypatch): + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234,'\ + 'ceph.wal_uuid=wal_uuid,ceph.db_device=/dbdevice' + source_wal_tags = \ + 'ceph.wal_uuid=uuid,ceph.wal_device=device,' \ + 'ceph.osd_id=0,ceph.type=wal' + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv3': wal_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + self.mock_volume = api.Volume(lv_name='target_volume1', lv_uuid='y', + vg_name='vg', + lv_path='/dev/VolGroup/target_volume', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + #find_associated_devices will call get_lvs() 4 times + # and it this needs results to be arranged that way + self.mock_volumes = [] + self.mock_volumes.append([data_vol, wal_vol]) + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([wal_vol]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph_cluster') + monkeypatch.setattr(system, 'chown', lambda path: 0) + + migrate.NewDB(argv=[ + '--osd-id', '1', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_db', + '--no-systemd']).main() + + n = len(self.mock_process_input) + assert n >= 5 + + assert self.mock_process_input[n - 5] == [ + 'lvchange', + '--deltag', 'ceph.db_device=/dbdevice', + '/dev/VolGroup/lv1'] + assert self.mock_process_input[n - 4] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=y', + '--addtag', 'ceph.db_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/lv1'] + + assert self.mock_process_input[n - 3].sort() == [ + 'lvchange', + '--addtag', 'ceph.wal_uuid=uuid', + '--addtag', 'ceph.osd_id=0', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.db_uuid=y', + '--addtag', 'ceph.db_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/target_volume'].sort() + + assert self.mock_process_input[n - 2] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=y', + '--addtag', 'ceph.db_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/lv3'] + + assert self.mock_process_input[n - 1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph_cluster-1', + '--dev-target', '/dev/VolGroup/target_volume', + '--command', 'bluefs-bdev-new-db'] + + @patch('os.getuid') + def test_newwal(self, m_getuid, monkeypatch, capsys): + m_getuid.return_value = 0 + + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234' + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + self.mock_volume = api.Volume(lv_name='target_volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/target_volume', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', self.mock_get_lv_by_fullname) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", lambda id: False) + + #find_associated_devices will call get_lvs() 4 times + # and it this needs results to be arranged that way + self.mock_volumes = [] + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + + monkeypatch.setattr(migrate, 'get_cluster_name', lambda osd_id, osd_fsid: 'cluster') + monkeypatch.setattr(system, 'chown', lambda path: 0) + + migrate.NewWAL(argv=[ + '--osd-id', '2', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_wal']).main() + + n = len(self.mock_process_input) + assert n >= 3 + + assert self.mock_process_input[n - 3] == [ + 'lvchange', + '--addtag', 'ceph.wal_uuid=y', + '--addtag', 'ceph.wal_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/lv1'] + + assert self.mock_process_input[n - 2].sort() == [ + 'lvchange', + '--addtag', 'ceph.osd_id=0', + '--addtag', 'ceph.type=wal', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.wal_uuid=y', + '--addtag', 'ceph.wal_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/target_volume'].sort() + + assert self.mock_process_input[n - 1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/cluster-2', + '--dev-target', '/dev/VolGroup/target_volume', + '--command', 'bluefs-bdev-new-wal'] + + def test_newwal_active_systemd(self, is_root, monkeypatch, capsys): + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234' + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + self.mock_volume = api.Volume(lv_name='target_volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/target_volume', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', self.mock_get_lv_by_fullname) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", lambda id: True) + + #find_associated_devices will call get_lvs() 4 times + # and it this needs results to be arranged that way + self.mock_volumes = [] + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + + monkeypatch.setattr(migrate, 'get_cluster_name', lambda osd_id, osd_fsid: 'cluster') + monkeypatch.setattr(system, 'chown', lambda path: 0) + + m = migrate.NewWAL(argv=[ + '--osd-id', '2', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_wal']) + + with pytest.raises(SystemExit) as error: + m.main() + + stdout, stderr = capsys.readouterr() + + assert 'Unable to attach new volume for OSD: 2' == str(error.value) + assert '--> OSD ID is running, stop it with: systemctl stop ceph-osd@2' == stderr.rstrip() + assert not stdout + + def test_newwal_no_systemd(self, is_root, monkeypatch): + source_tags = \ + 'ceph.osd_id=0,ceph.type=data,ceph.osd_fsid=1234' + + data_vol = api.Volume(lv_name='volume1', lv_uuid='datauuid', vg_name='vg', + lv_path='/dev/VolGroup/lv1', lv_tags=source_tags) + + self.mock_single_volumes = {'/dev/VolGroup/lv1': data_vol} + + monkeypatch.setattr(migrate.api, 'get_first_lv', self.mock_get_first_lv) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + self.mock_volume = api.Volume(lv_name='target_volume1', lv_uuid='y', vg_name='vg', + lv_path='/dev/VolGroup/target_volume', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', self.mock_get_lv_by_fullname) + + #find_associated_devices will call get_lvs() 4 times + # and it this needs results to be arranged that way + self.mock_volumes = [] + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([data_vol]) + self.mock_volumes.append([]) + self.mock_volumes.append([]) + + monkeypatch.setattr(migrate.api, 'get_lvs', self.mock_get_lvs) + + monkeypatch.setattr(migrate, 'get_cluster_name', lambda osd_id, osd_fsid: 'cluster') + monkeypatch.setattr(system, 'chown', lambda path: 0) + + migrate.NewWAL(argv=[ + '--osd-id', '2', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--target', 'vgname/new_wal', + '--no-systemd']).main() + + n = len(self.mock_process_input) + assert n >= 3 + + assert self.mock_process_input[n - 3] == [ + 'lvchange', + '--addtag', 'ceph.wal_uuid=y', + '--addtag', 'ceph.wal_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/lv1'] + + assert self.mock_process_input[n - 2].sort() == [ + 'lvchange', + '--addtag', 'ceph.osd_id=0', + '--addtag', 'ceph.type=wal', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.wal_uuid=y', + '--addtag', 'ceph.wal_device=/dev/VolGroup/target_volume', + '/dev/VolGroup/target_volume'].sort() + + assert self.mock_process_input[n - 1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/cluster-2', + '--dev-target', '/dev/VolGroup/target_volume', + '--command', 'bluefs-bdev-new-wal'] + +class TestMigrate(object): + + mock_volume = None + def mock_get_lv_by_fullname(self, *args, **kwargs): + return self.mock_volume + + mock_process_input = [] + def mock_process(self, *args, **kwargs): + self.mock_process_input.append(args[0]); + return ('', '', 0) + + mock_single_volumes = {} + def mock_get_first_lv(self, *args, **kwargs): + p = kwargs['filters']['lv_path'] + return self.mock_single_volumes[p] + + mock_volumes = [] + def mock_get_lvs(self, *args, **kwargs): + return self.mock_volumes.pop(0) + + def test_get_source_devices(self, monkeypatch): + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2', lv_uuid='y', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags='ceph.osd_id=5,ceph.osd_type=db') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + + argv = [ + '--osd-id', '2', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--from', 'data', 'wal', + '--target', 'vgname/new_wal' + ] + m = migrate.Migrate(argv=argv) + m.args = m.make_parser('ceph-volume lvm migation', 'help').parse_args(argv) + res_devices = m.get_source_devices(devices) + + assert 2 == len(res_devices) + assert devices[0] == res_devices[0] + assert devices[2] == res_devices[1] + + argv = [ + '--osd-id', '2', + '--osd-fsid', '55BD4219-16A7-4037-BC20-0F158EFCC83D', + '--from', 'db', 'wal', 'data', + '--target', 'vgname/new_wal' + ] + m = migrate.Migrate(argv=argv) + m.args = m.make_parser('ceph-volume lvm migation', 'help').parse_args(argv) + res_devices = m.get_source_devices(devices) + + assert 3 == len(res_devices) + assert devices[0] == res_devices[0] + assert devices[1] == res_devices[1] + assert devices[2] == res_devices[2] + + + def test_migrate_without_args(self, capsys): + help_msg = """ +Moves BlueFS data from source volume(s) to the target one, source +volumes (except the main (i.e. data or block) one) are removed on +success. LVM volumes are permitted for Target only, both already +attached or new logical one. In the latter case it is attached to OSD +replacing one of the source devices. Following replacement rules apply +(in the order of precedence, stop on the first match): +* if source list has DB volume - target device replaces it. +* if source list has WAL volume - target device replace it. +* if source list has slow volume only - operation is not permitted, + requires explicit allocation via new-db/new-wal command. + +Example calls for supported scenarios: + + Moves BlueFS data from main device to LV already attached as DB: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data --target vgname/db + + Moves BlueFS data from shared main device to LV which will be attached + as a new DB: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data --target vgname/new_db + + Moves BlueFS data from DB device to new LV, DB is replaced: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from db --target vgname/new_db + + Moves BlueFS data from main and DB devices to new LV, DB is replaced: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data db --target vgname/new_db + + Moves BlueFS data from main, DB and WAL devices to new LV, WAL is + removed and DB is replaced: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from data db wal --target vgname/new_db + + Moves BlueFS data from main, DB and WAL devices to main device, WAL + and DB are removed: + + ceph-volume lvm migrate --osd-id 1 --osd-fsid --from db wal --target vgname/data + +""" + m = migrate.Migrate(argv=[]) + m.main() + stdout, stderr = capsys.readouterr() + assert help_msg in stdout + assert not stderr + + + @patch('os.getuid') + def test_migrate_data_db_to_new_db(self, m_getuid, monkeypatch): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2_new', lv_uuid='new-db-uuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2_new', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'data', 'db', 'wal', + '--target', 'vgname/new_wal']) + m.main() + + n = len(self.mock_process_input) + assert n >= 5 + + assert self. mock_process_input[n-5] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=2', + '--deltag', 'ceph.type=db', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv2'] + + assert self. mock_process_input[n-4] == [ + 'lvchange', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-3] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-2] == [ + 'lvchange', + '--addtag', 'ceph.osd_id=2', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.cluster_name=ceph', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv2_new'] + + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/dev/VolGroup/lv2_new', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.db'] + + def test_migrate_data_db_to_new_db_active_systemd(self, is_root, monkeypatch, capsys): + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2_new', lv_uuid='new-db-uuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2_new', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: True) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'data', 'db', 'wal', + '--target', 'vgname/new_wal']) + + with pytest.raises(SystemExit) as error: + m.main() + + stdout, stderr = capsys.readouterr() + + assert 'Unable to migrate devices associated with OSD ID: 2' == str(error.value) + assert '--> OSD is running, stop it with: systemctl stop ceph-osd@2' == stderr.rstrip() + assert not stdout + + def test_migrate_data_db_to_new_db_no_systemd(self, is_root, monkeypatch): + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2_new', lv_uuid='new-db-uuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2_new', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'data', 'db', 'wal', + '--target', 'vgname/new_wal', + '--no-systemd']) + m.main() + + n = len(self.mock_process_input) + assert n >= 5 + + assert self. mock_process_input[n-5] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=2', + '--deltag', 'ceph.type=db', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv2'] + + assert self. mock_process_input[n-4] == [ + 'lvchange', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-3] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-2] == [ + 'lvchange', + '--addtag', 'ceph.osd_id=2', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.cluster_name=ceph', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv2_new'] + + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/dev/VolGroup/lv2_new', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.db'] + + @patch('os.getuid') + def test_migrate_data_db_to_new_db_skip_wal(self, m_getuid, monkeypatch): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2_new', lv_uuid='new-db-uuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2_new', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'data', 'db', + '--target', 'vgname/new_wal']) + m.main() + + n = len(self.mock_process_input) + assert n >= 7 + + assert self. mock_process_input[n-7] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=2', + '--deltag', 'ceph.type=db', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv2'] + + assert self. mock_process_input[n-6] == [ + 'lvchange', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-5] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-4] == [ + 'lvchange', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv3'] + + assert self. mock_process_input[n-3] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv3'] + + assert self. mock_process_input[n-2] == [ + 'lvchange', + '--addtag', 'ceph.osd_id=2', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.cluster_name=ceph', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv2_new'] + + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/dev/VolGroup/lv2_new', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.db'] + + @patch('os.getuid') + def test_migrate_data_db_wal_to_new_db(self, m_getuid, monkeypatch): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_wal_tags = 'ceph.osd_id=0,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2_new', lv_uuid='new-db-uuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2_new', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'data', 'db', 'wal', + '--target', 'vgname/new_wal']) + m.main() + + n = len(self.mock_process_input) + assert n >= 6 + + assert self. mock_process_input[n-6] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=2', + '--deltag', 'ceph.type=db', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '/dev/VolGroup/lv2'] + + assert self. mock_process_input[n-5] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=0', + '--deltag', 'ceph.type=wal', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv3'] + + assert self. mock_process_input[n-4] == [ + 'lvchange', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-3] == [ + 'lvchange', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv1'] + + assert self. mock_process_input[n-2] == [ + 'lvchange', + '--addtag', 'ceph.osd_id=2', + '--addtag', 'ceph.type=db', + '--addtag', 'ceph.osd_fsid=1234', + '--addtag', 'ceph.cluster_name=ceph', + '--addtag', 'ceph.db_uuid=new-db-uuid', + '--addtag', 'ceph.db_device=/dev/VolGroup/lv2_new', + '/dev/VolGroup/lv2_new'] + + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/dev/VolGroup/lv2_new', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.db', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.wal'] + + @patch('os.getuid') + def test_dont_migrate_data_db_wal_to_new_data(self, + m_getuid, + monkeypatch, + capsys): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = api.Volume(lv_name='volume2_new', lv_uuid='new-db-uuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2_new', + lv_tags='') + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'data', + '--target', 'vgname/new_data']) + + with pytest.raises(SystemExit) as error: + m.main() + stdout, stderr = capsys.readouterr() + expected = 'Unable to migrate to : vgname/new_data' + assert expected in str(error.value) + expected = 'Unable to determine new volume type,' + ' please use new-db or new-wal command before.' + assert expected in stderr + + @patch('os.getuid') + def test_dont_migrate_db_to_wal(self, + m_getuid, + monkeypatch, + capsys): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = wal_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', + '--target', 'vgname/wal']) + + with pytest.raises(SystemExit) as error: + m.main() + stdout, stderr = capsys.readouterr() + expected = 'Unable to migrate to : vgname/wal' + assert expected in str(error.value) + expected = 'Migrate to WAL is not supported' + assert expected in stderr + + @patch('os.getuid') + def test_migrate_data_db_to_db(self, + m_getuid, + monkeypatch, + capsys): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = db_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', 'data', + '--target', 'vgname/db']) + + m.main() + + n = len(self.mock_process_input) + assert n >= 1 + for s in self.mock_process_input: + print(s) + + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/var/lib/ceph/osd/ceph-2/block.db', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block'] + + def test_migrate_data_db_to_db_active_systemd(self, is_root, monkeypatch, capsys): + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = db_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: True) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', 'data', + '--target', 'vgname/db']) + + with pytest.raises(SystemExit) as error: + m.main() + + stdout, stderr = capsys.readouterr() + + assert 'Unable to migrate devices associated with OSD ID: 2' == str(error.value) + assert '--> OSD is running, stop it with: systemctl stop ceph-osd@2' == stderr.rstrip() + assert not stdout + + def test_migrate_data_db_to_db_no_systemd(self, is_root, monkeypatch): + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = db_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', 'data', + '--target', 'vgname/db', + '--no-systemd']) + + m.main() + + n = len(self.mock_process_input) + assert n >= 1 + for s in self.mock_process_input: + print(s) + + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/var/lib/ceph/osd/ceph-2/block.db', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block'] + + @patch('os.getuid') + def test_migrate_data_wal_to_db(self, + m_getuid, + monkeypatch, + capsys): + m_getuid.return_value = 0 + + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = db_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: False) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', 'data', 'wal', + '--target', 'vgname/db']) + + m.main() + + n = len(self.mock_process_input) + assert n >= 1 + for s in self.mock_process_input: + print(s) + + assert self. mock_process_input[n-4] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=2', + '--deltag', 'ceph.type=wal', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv3'] + assert self. mock_process_input[n-3] == [ + 'lvchange', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv1'] + assert self. mock_process_input[n-2] == [ + 'lvchange', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv2'] + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/var/lib/ceph/osd/ceph-2/block.db', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.wal'] + + def test_migrate_data_wal_to_db_active_systemd(self, is_root, monkeypatch, capsys): + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = db_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr("ceph_volume.systemd.systemctl.osd_is_active", + lambda id: True) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', 'data', 'wal', + '--target', 'vgname/db']) + + with pytest.raises(SystemExit) as error: + m.main() + + stdout, stderr = capsys.readouterr() + + assert 'Unable to migrate devices associated with OSD ID: 2' == str(error.value) + assert '--> OSD is running, stop it with: systemctl stop ceph-osd@2' == stderr.rstrip() + assert not stdout + + def test_migrate_data_wal_to_db_no_systemd(self, is_root, monkeypatch): + source_tags = 'ceph.osd_id=2,ceph.type=data,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_db_tags = 'ceph.osd_id=2,ceph.type=db,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + source_wal_tags = 'ceph.osd_id=2,ceph.type=wal,ceph.osd_fsid=1234,' \ + 'ceph.cluster_name=ceph,ceph.db_uuid=dbuuid,ceph.db_device=db_dev,' \ + 'ceph.wal_uuid=waluuid,ceph.wal_device=wal_dev' + + data_vol = api.Volume(lv_name='volume1', + lv_uuid='datauuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv1', + lv_tags=source_tags) + db_vol = api.Volume(lv_name='volume2', + lv_uuid='dbuuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv2', + lv_tags=source_db_tags) + + wal_vol = api.Volume(lv_name='volume3', + lv_uuid='waluuid', + vg_name='vg', + lv_path='/dev/VolGroup/lv3', + lv_tags=source_wal_tags) + + self.mock_single_volumes = { + '/dev/VolGroup/lv1': data_vol, + '/dev/VolGroup/lv2': db_vol, + '/dev/VolGroup/lv3': wal_vol, + } + monkeypatch.setattr(migrate.api, 'get_first_lv', + self.mock_get_first_lv) + + self.mock_volume = db_vol + monkeypatch.setattr(api, 'get_lv_by_fullname', + self.mock_get_lv_by_fullname) + + self.mock_process_input = [] + monkeypatch.setattr(process, 'call', self.mock_process) + + devices = [] + devices.append([Device('/dev/VolGroup/lv1'), 'block']) + devices.append([Device('/dev/VolGroup/lv2'), 'db']) + devices.append([Device('/dev/VolGroup/lv3'), 'wal']) + + monkeypatch.setattr(migrate, 'find_associated_devices', + lambda osd_id, osd_fsid: devices) + + monkeypatch.setattr(migrate, 'get_cluster_name', + lambda osd_id, osd_fsid: 'ceph') + monkeypatch.setattr(system, 'chown', lambda path: 0) + m = migrate.Migrate(argv=[ + '--osd-id', '2', + '--osd-fsid', '1234', + '--from', 'db', 'data', 'wal', + '--target', 'vgname/db', + '--no-systemd']) + + m.main() + + n = len(self.mock_process_input) + assert n >= 1 + for s in self.mock_process_input: + print(s) + + assert self. mock_process_input[n-4] == [ + 'lvchange', + '--deltag', 'ceph.osd_id=2', + '--deltag', 'ceph.type=wal', + '--deltag', 'ceph.osd_fsid=1234', + '--deltag', 'ceph.cluster_name=ceph', + '--deltag', 'ceph.db_uuid=dbuuid', + '--deltag', 'ceph.db_device=db_dev', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv3'] + assert self. mock_process_input[n-3] == [ + 'lvchange', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv1'] + assert self. mock_process_input[n-2] == [ + 'lvchange', + '--deltag', 'ceph.wal_uuid=waluuid', + '--deltag', 'ceph.wal_device=wal_dev', + '/dev/VolGroup/lv2'] + assert self. mock_process_input[n-1] == [ + 'ceph-bluestore-tool', + '--path', '/var/lib/ceph/osd/ceph-2', + '--dev-target', '/var/lib/ceph/osd/ceph-2/block.db', + '--command', 'bluefs-bdev-migrate', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block', + '--devs-source', '/var/lib/ceph/osd/ceph-2/block.wal'] diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/raw/test_list.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/raw/test_list.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/devices/raw/test_list.py 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/devices/raw/test_list.py 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,235 @@ +import pytest +from mock.mock import patch +from ceph_volume.devices import raw + +# Sample lsblk output is below that overviews the test scenario. (--json output for reader clarity) +# - sda and all its children are used for the OS +# - sdb is a bluestore OSD with phantom Atari partitions +# - sdc is an empty disk +# - sdd has 2 LVM device children +# > lsblk --paths --json +# { +# "blockdevices": [ +# {"name": "/dev/sda", "maj:min": "8:0", "rm": "0", "size": "128G", "ro": "0", "type": "disk", "mountpoint": null, +# "children": [ +# {"name": "/dev/sda1", "maj:min": "8:1", "rm": "0", "size": "487M", "ro": "0", "type": "part", "mountpoint": null}, +# {"name": "/dev/sda2", "maj:min": "8:2", "rm": "0", "size": "1.9G", "ro": "0", "type": "part", "mountpoint": null}, +# {"name": "/dev/sda3", "maj:min": "8:3", "rm": "0", "size": "125.6G", "ro": "0", "type": "part", "mountpoint": "/etc/hosts"} +# ] +# }, +# {"name": "/dev/sdb", "maj:min": "8:16", "rm": "0", "size": "1T", "ro": "0", "type": "disk", "mountpoint": null, +# "children": [ +# {"name": "/dev/sdb2", "maj:min": "8:18", "rm": "0", "size": "48G", "ro": "0", "type": "part", "mountpoint": null}, +# {"name": "/dev/sdb3", "maj:min": "8:19", "rm": "0", "size": "6M", "ro": "0", "type": "part", "mountpoint": null} +# ] +# }, +# {"name": "/dev/sdc", "maj:min": "8:32", "rm": "0", "size": "1T", "ro": "0", "type": "disk", "mountpoint": null}, +# {"name": "/dev/sdd", "maj:min": "8:48", "rm": "0", "size": "1T", "ro": "0", "type": "disk", "mountpoint": null, +# "children": [ +# {"name": "/dev/mapper/ceph--osd--block--1", "maj:min": "253:0", "rm": "0", "size": "512G", "ro": "0", "type": "lvm", "mountpoint": null}, +# {"name": "/dev/mapper/ceph--osd--block--2", "maj:min": "253:1", "rm": "0", "size": "512G", "ro": "0", "type": "lvm", "mountpoint": null} +# ] +# } +# ] +# } + +def _devices_side_effect(): + return { + "/dev/sda": {}, + "/dev/sda1": {}, + "/dev/sda2": {}, + "/dev/sda3": {}, + "/dev/sdb": {}, + "/dev/sdb2": {}, + "/dev/sdb3": {}, + "/dev/sdc": {}, + "/dev/sdd": {}, + "/dev/mapper/ceph--osd--block--1": {}, + "/dev/mapper/ceph--osd--block--2": {}, + } + +def _lsblk_list_output(): + return [ + '/dev/sda', + '/dev/sda1', + '/dev/sda2', + '/dev/sda3', + '/dev/sdb', + '/dev/sdb2', + '/dev/sdb3', + '/dev/sdc', + '/dev/sdd', + '/dev/mapper/ceph--osd--block--1', + '/dev/mapper/ceph--osd--block--2', + ] + +# dummy lsblk output for device with optional parent output +def _lsblk_output(dev, parent=None): + if parent is None: + parent = "" + ret = 'NAME="{}" KNAME="{}" PKNAME="{}"'.format(dev, dev, parent) + return [ret] # needs to be in a list form + +def _bluestore_tool_label_output_sdb(): + return '''{ + "/dev/sdb": { + "osd_uuid": "sdb-uuid", + "size": 1099511627776, + "btime": "2021-07-23T16:02:22.809186+0000", + "description": "main", + "bfm_blocks": "268435456", + "bfm_blocks_per_key": "128", + "bfm_bytes_per_block": "4096", + "bfm_size": "1099511627776", + "bluefs": "1", + "ceph_fsid": "sdb-fsid", + "kv_backend": "rocksdb", + "magic": "ceph osd volume v026", + "mkfs_done": "yes", + "osd_key": "AQAO6PpgK+y4CBAAixq/X7OVimbaezvwD/cDmg==", + "ready": "ready", + "require_osd_release": "16", + "whoami": "0" + } +}''' + +def _bluestore_tool_label_output_sdb2(): + return '''{ + "/dev/sdb2": { + "osd_uuid": "sdb2-uuid", + "size": 1099511627776, + "btime": "2021-07-23T16:02:22.809186+0000", + "description": "main", + "bfm_blocks": "268435456", + "bfm_blocks_per_key": "128", + "bfm_bytes_per_block": "4096", + "bfm_size": "1099511627776", + "bluefs": "1", + "ceph_fsid": "sdb2-fsid", + "kv_backend": "rocksdb", + "magic": "ceph osd volume v026", + "mkfs_done": "yes", + "osd_key": "AQAO6PpgK+y4CBAAixq/X7OVimbaezvwD/cDmg==", + "ready": "ready", + "require_osd_release": "16", + "whoami": "2" + } +}''' + +def _bluestore_tool_label_output_dm_okay(): + return '''{ + "/dev/mapper/ceph--osd--block--1": { + "osd_uuid": "lvm-1-uuid", + "size": 549751619584, + "btime": "2021-07-23T16:04:37.881060+0000", + "description": "main", + "bfm_blocks": "134216704", + "bfm_blocks_per_key": "128", + "bfm_bytes_per_block": "4096", + "bfm_size": "549751619584", + "bluefs": "1", + "ceph_fsid": "lvm-1-fsid", + "kv_backend": "rocksdb", + "magic": "ceph osd volume v026", + "mkfs_done": "yes", + "osd_key": "AQCU6Ppgz+UcIRAAh6IUjtPjiXBlEXfwO8ixzw==", + "ready": "ready", + "require_osd_release": "16", + "whoami": "2" + } +}''' + +def _process_call_side_effect(command, **kw): + if "lsblk" in command: + if "/dev/" in command[-1]: + dev = command[-1] + if dev == "/dev/sda1" or dev == "/dev/sda2" or dev == "/dev/sda3": + return _lsblk_output(dev, parent="/dev/sda"), '', 0 + if dev == "/dev/sdb2" or dev == "/dev/sdb3": + return _lsblk_output(dev, parent="/dev/sdb"), '', 0 + if dev == "/dev/sda" or dev == "/dev/sdb" or dev == "/dev/sdc" or dev == "/dev/sdd": + return _lsblk_output(dev), '', 0 + if "mapper" in dev: + return _lsblk_output(dev, parent="/dev/sdd"), '', 0 + pytest.fail('dev {} needs behavior specified for it'.format(dev)) + if "/dev/" not in command: + return _lsblk_list_output(), '', 0 + pytest.fail('command {} needs behavior specified for it'.format(command)) + + if "ceph-bluestore-tool" in command: + if "/dev/sdb" in command: + # sdb is a bluestore OSD + return _bluestore_tool_label_output_sdb(), '', 0 + if "/dev/sdb2" in command: + # sdb2 is a phantom atari partition that appears to have some valid bluestore info + return _bluestore_tool_label_output_sdb2(), '', 0 + if "/dev/mapper/ceph--osd--block--1" in command: + # dm device 1 is a valid bluestore OSD (the other is corrupted/invalid) + return _bluestore_tool_label_output_dm_okay(), '', 0 + # sda and children, sdb's children, sdc, sdd, dm device 2 all do NOT have bluestore OSD data + return [], 'fake No such file or directory error', 1 + pytest.fail('command {} needs behavior specified for it'.format(command)) + +def _has_bluestore_label_side_effect(disk_path): + if "/dev/sda" in disk_path: + return False # disk and all children are for the OS + if disk_path == "/dev/sdb": + return True # sdb is a valid bluestore OSD + if disk_path == "/dev/sdb2": + return True # sdb2 appears to be a valid bluestore OSD even though it should not be + if disk_path == "/dev/sdc": + return False # empty disk + if disk_path == "/dev/sdd": + return False # has LVM subdevices + if disk_path == "/dev/mapper/ceph--osd--block--1": + return True # good OSD + if disk_path == "/dev/mapper/ceph--osd--block--2": + return False # corrupted + pytest.fail('device {} needs behavior specified for it'.format(disk_path)) + +class TestList(object): + + @patch('ceph_volume.util.device.disk.get_devices') + @patch('ceph_volume.util.disk.has_bluestore_label') + @patch('ceph_volume.process.call') + def test_raw_list(self, patched_call, patched_bluestore_label, patched_get_devices): + raw.list.logger.setLevel("DEBUG") + patched_call.side_effect = _process_call_side_effect + patched_bluestore_label.side_effect = _has_bluestore_label_side_effect + patched_get_devices.side_effect = _devices_side_effect + + result = raw.list.List([]).generate() + patched_call.assert_any_call(['lsblk', '--paths', '--output=NAME', '--noheadings', '--list']) + assert len(result) == 2 + + sdb = result['sdb-uuid'] + assert sdb['osd_uuid'] == 'sdb-uuid' + assert sdb['osd_id'] == 0 + assert sdb['device'] == '/dev/sdb' + assert sdb['ceph_fsid'] == 'sdb-fsid' + assert sdb['type'] == 'bluestore' + + lvm1 = result['lvm-1-uuid'] + assert lvm1['osd_uuid'] == 'lvm-1-uuid' + assert lvm1['osd_id'] == 2 + assert lvm1['device'] == '/dev/mapper/ceph--osd--block--1' + assert lvm1['ceph_fsid'] == 'lvm-1-fsid' + assert lvm1['type'] == 'bluestore' + + @patch('ceph_volume.util.device.disk.get_devices') + @patch('ceph_volume.util.disk.has_bluestore_label') + @patch('ceph_volume.process.call') + def test_raw_list_with_OSError(self, patched_call, patched_bluestore_label, patched_get_devices): + def _has_bluestore_label_side_effect_with_OSError(device_path): + if device_path == "/dev/sdd": + raise OSError('fake OSError') + return _has_bluestore_label_side_effect(device_path) + + raw.list.logger.setLevel("DEBUG") + patched_call.side_effect = _process_call_side_effect + patched_bluestore_label.side_effect = _has_bluestore_label_side_effect_with_OSError + patched_get_devices.side_effect = _devices_side_effect + + result = raw.list.List([]).generate() + assert len(result) == 1 + assert 'sdb-uuid' in result diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/batch/tox.ini 2021-09-16 14:27:19.000000000 +0000 @@ -12,11 +12,9 @@ sleep passenv=* setenv= - ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config - ANSIBLE_ACTION_PLUGINS = {envdir}/tmp/ceph-ansible/plugins/actions + ANSIBLE_CONFIG = {envdir}/tmp/ceph-ansible/ansible.cfg + ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey ANSIBLE_STDOUT_CALLBACK = debug - ANSIBLE_RETRY_FILES_ENABLED = False - ANSIBLE_SSH_RETRIES = 5 VAGRANT_CWD = {changedir} CEPH_VOLUME_DEBUG = 1 DEBIAN_FRONTEND=noninteractive @@ -53,7 +51,7 @@ ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml # test cluster state using testinfra - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # reboot all vms - attempt bash {toxinidir}/../scripts/vagrant_reload.sh {env:VAGRANT_UP_FLAGS:"--no-provision"} {posargs:--provider=virtualbox} @@ -62,13 +60,13 @@ sleep 30 # retest to ensure cluster came back up correctly after rebooting - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # destroy an OSD, zap it's device and recreate it using it's ID ansible-playbook -vv -i {changedir}/hosts {changedir}/test.yml # retest to ensure cluster came back up correctly - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # test zap OSDs by ID ansible-playbook -vv -i {changedir}/hosts {changedir}/test_zap.yml diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/create/test.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/create/test.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/create/test.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/create/test.yml 2021-09-16 14:27:19.000000000 +0000 @@ -17,12 +17,25 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.{{ item }}" + with_items: + - 0 + - 2 - name: destroy osd.2 command: "ceph --cluster {{ cluster }} osd destroy osd.2 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/dmcrypt/test.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/dmcrypt/test.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/dmcrypt/test.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/bluestore/dmcrypt/test.yml 2021-09-16 14:27:19.000000000 +0000 @@ -15,12 +15,25 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.{{ item }}" + with_items: + - 0 + - 2 - name: destroy osd.2 command: "ceph --cluster {{ cluster }} osd destroy osd.2 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds become: yes @@ -68,9 +81,15 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.0" - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/create/test.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/create/test.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/create/test.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/create/test.yml 2021-09-16 14:27:19.000000000 +0000 @@ -17,13 +17,25 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.{{ item }}" + with_items: + - 0 + - 2 - name: destroy osd.2 command: "ceph --cluster {{ cluster }} osd destroy osd.2 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" - + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds become: yes diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/dmcrypt/test.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/dmcrypt/test.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/dmcrypt/test.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/centos8/filestore/dmcrypt/test.yml 2021-09-16 14:27:19.000000000 +0000 @@ -17,13 +17,25 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.{{ item }}" + with_items: + - 0 + - 2 - name: destroy osd.2 command: "ceph --cluster {{ cluster }} osd destroy osd.2 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" - + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds become: yes diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_bluestore.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_bluestore.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_bluestore.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_bluestore.yml 2021-09-16 14:27:19.000000000 +0000 @@ -17,12 +17,25 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.{{ item }}" + with_items: + - 0 + - 2 - name: destroy osd.2 command: "ceph --cluster {{ cluster }} osd destroy osd.2 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_filestore.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_filestore.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_filestore.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/playbooks/test_filestore.yml 2021-09-16 14:27:19.000000000 +0000 @@ -17,13 +17,25 @@ - hosts: mons become: yes tasks: + - name: mark osds down + command: "ceph --cluster {{ cluster }} osd down osd.{{ item }}" + with_items: + - 0 + - 2 - name: destroy osd.2 command: "ceph --cluster {{ cluster }} osd destroy osd.2 --yes-i-really-mean-it" + register: result + retries: 30 + delay: 1 + until: result is succeeded - name: destroy osd.0 command: "ceph --cluster {{ cluster }} osd destroy osd.0 --yes-i-really-mean-it" - + register: result + retries: 30 + delay: 1 + until: result is succeeded - hosts: osds become: yes diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/lvm/tox.ini 2021-09-16 14:27:19.000000000 +0000 @@ -12,11 +12,9 @@ sleep passenv=* setenv= - ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config - ANSIBLE_ACTION_PLUGINS = {envdir}/tmp/ceph-ansible/plugins/actions + ANSIBLE_CONFIG = {envdir}/tmp/ceph-ansible/ansible.cfg + ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey ANSIBLE_STDOUT_CALLBACK = debug - ANSIBLE_RETRY_FILES_ENABLED = False - ANSIBLE_SSH_RETRIES = 5 VAGRANT_CWD = {changedir} CEPH_VOLUME_DEBUG = 1 DEBIAN_FRONTEND=noninteractive @@ -53,7 +51,7 @@ ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml # test cluster state using testinfra - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # reboot all vms - attempt bash {toxinidir}/../scripts/vagrant_reload.sh {env:VAGRANT_UP_FLAGS:"--no-provision"} {posargs:--provider=virtualbox} @@ -62,12 +60,12 @@ sleep 30 # retest to ensure cluster came back up correctly after rebooting - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # destroy an OSD, zap it's device and recreate it using it's ID ansible-playbook -vv -i {changedir}/hosts {changedir}/test.yml # retest to ensure cluster came back up correctly - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests vagrant destroy {env:VAGRANT_DESTROY_FLAGS:"--force"} diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/playbooks/deploy.yml 2021-09-16 14:27:19.000000000 +0000 @@ -75,8 +75,8 @@ - name: install required packages for fedora > 23 raw: sudo dnf -y install python2-dnf libselinux-python ntp when: - - ansible_distribution == 'Fedora' - - ansible_distribution_major_version|int >= 23 + - ansible_facts['distribution'] == 'Fedora' + - ansible_facts['distribution_major_version']|int >= 23 - name: check if it is atomic host stat: @@ -120,7 +120,7 @@ dest: "/usr/lib/python3.6/site-packages" use_ssh_args: true when: - - ansible_os_family == "RedHat" + - ansible_facts['os_family'] == "RedHat" - inventory_hostname in groups.get(osd_group_name, []) - name: rsync ceph-volume to test nodes on ubuntu @@ -129,7 +129,7 @@ dest: "/usr/lib/python2.7/dist-packages" use_ssh_args: true when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - inventory_hostname in groups.get(osd_group_name, []) - name: run ceph-config role diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/functional/simple/tox.ini 2021-09-16 14:27:19.000000000 +0000 @@ -12,11 +12,9 @@ cp passenv=* setenv= - ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config - ANSIBLE_ACTION_PLUGINS = {envdir}/tmp/ceph-ansible/plugins/actions + ANSIBLE_CONFIG = {envdir}/tmp/ceph-ansible/ansible.cfg + ANSIBLE_SSH_ARGS = -F {changedir}/vagrant_ssh_config -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey ANSIBLE_STDOUT_CALLBACK = debug - ANSIBLE_RETRY_FILES_ENABLED = False - ANSIBLE_SSH_RETRIES = 5 VAGRANT_CWD = {changedir} CEPH_VOLUME_DEBUG = 1 DEBIAN_FRONTEND=noninteractive @@ -43,7 +41,7 @@ ansible-playbook -vv -i {changedir}/hosts {envdir}/tmp/ceph-ansible/tests/functional/setup.yml # test cluster state testinfra - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests # make ceph-volume simple take over all the OSDs that got deployed, disabling ceph-disk ansible-playbook -vv -i {changedir}/hosts {changedir}/test.yml @@ -55,6 +53,6 @@ sleep 120 # retest to ensure cluster came back up correctly after rebooting - py.test -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests + py.test --reruns 5 --reruns-delay 10 -n 4 --sudo -v --connection=ansible --ssh-config={changedir}/vagrant_ssh_config --ansible-inventory={changedir}/hosts {toxinidir}/../tests vagrant destroy {env:VAGRANT_DESTROY_FLAGS:"--force"} diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/util/test_arg_validators.py 2021-09-16 14:27:19.000000000 +0000 @@ -80,10 +80,10 @@ def setup(self): self.validator = arg_validators.ValidDevice() - def test_path_is_valid(self, fake_call): + def test_path_is_valid(self, fake_call, patch_bluestore_label): result = self.validator('/') assert result.abspath == '/' - def test_path_is_invalid(self, fake_call): + def test_path_is_invalid(self, fake_call, patch_bluestore_label): with pytest.raises(argparse.ArgumentError): self.validator('/device/does/not/exist') diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/tests/util/test_device.py ceph-16.2.6/src/ceph-volume/ceph_volume/tests/util/test_device.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/tests/util/test_device.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/tests/util/test_device.py 2021-09-16 14:27:19.000000000 +0000 @@ -2,6 +2,7 @@ from copy import deepcopy from ceph_volume.util import device from ceph_volume.api import lvm as api +from mock.mock import patch, mock_open class TestDevice(object): @@ -124,7 +125,7 @@ def test_is_partition(self, device_info): data = {"/dev/sda1": {"foo": "bar"}} - lsblk = {"TYPE": "part"} + lsblk = {"TYPE": "part", "PKNAME": "sda"} device_info(devices=data, lsblk=lsblk) disk = device.Device("/dev/sda1") assert disk.is_partition @@ -138,14 +139,14 @@ def test_is_not_lvm_memeber(self, device_info): data = {"/dev/sda1": {"foo": "bar"}} - lsblk = {"TYPE": "part"} + lsblk = {"TYPE": "part", "PKNAME": "sda"} device_info(devices=data, lsblk=lsblk) disk = device.Device("/dev/sda1") assert not disk.is_lvm_member def test_is_lvm_memeber(self, device_info): data = {"/dev/sda1": {"foo": "bar"}} - lsblk = {"TYPE": "part"} + lsblk = {"TYPE": "part", "PKNAME": "sda"} device_info(devices=data, lsblk=lsblk) disk = device.Device("/dev/sda1") assert not disk.is_lvm_member @@ -258,6 +259,14 @@ assert not disk.available assert "Has BlueStore device label" in disk.rejected_reasons + def test_reject_device_with_oserror(self, monkeypatch, patch_bluestore_label, device_info): + patch_bluestore_label.side_effect = OSError('test failure') + lsblk = {"TYPE": "disk"} + device_info(lsblk=lsblk) + disk = device.Device("/dev/sda") + assert not disk.available + assert "Failed to determine if device is BlueStore" in disk.rejected_reasons + @pytest.mark.usefixtures("device_info_not_ceph_disk_member", "disable_kernel_queries") def test_is_not_ceph_disk_member_lsblk(self, patch_bluestore_label): @@ -306,7 +315,7 @@ def test_used_by_ceph(self, device_info, monkeypatch, ceph_type): data = {"/dev/sda": {"foo": "bar"}} - lsblk = {"TYPE": "part"} + lsblk = {"TYPE": "part", "PKNAME": "sda"} FooPVolume = api.PVolume(pv_name='/dev/sda', pv_uuid="0000", lv_uuid="0000", pv_tags={}, vg_name="vg") pvolumes = [] @@ -333,7 +342,7 @@ pvolumes = [] pvolumes.append(FooPVolume) data = {"/dev/sda": {"foo": "bar"}} - lsblk = {"TYPE": "part"} + lsblk = {"TYPE": "part", "PKNAME": "sda"} lv_data = {"lv_path": "vg/lv", "vg_name": "vg", "lv_uuid": "0000", "tags": {"ceph.osd_id": 0, "ceph.type": "journal"}} monkeypatch.setattr(api, 'get_pvs', lambda **kwargs: pvolumes) @@ -348,31 +357,41 @@ disk = device.Device("/dev/sda") assert disk._get_device_id() == 'ID_VENDOR_ID_MODEL_ID_SCSI_SERIAL' + def test_has_bluestore_label(self): + # patch device.Device __init__ function to do nothing since we want to only test the + # low-level behavior of has_bluestore_label + with patch.object(device.Device, "__init__", lambda self, path, with_lsm=False: None): + disk = device.Device("/dev/sda") + disk.abspath = "/dev/sda" + with patch('builtins.open', mock_open(read_data=b'bluestore block device\n')): + assert disk.has_bluestore_label + with patch('builtins.open', mock_open(read_data=b'not a bluestore block device\n')): + assert not disk.has_bluestore_label class TestDeviceEncryption(object): def test_partition_is_not_encrypted_lsblk(self, device_info): - lsblk = {'TYPE': 'part', 'FSTYPE': 'xfs'} + lsblk = {'TYPE': 'part', 'FSTYPE': 'xfs', 'PKNAME': 'sda'} device_info(lsblk=lsblk) disk = device.Device("/dev/sda") assert disk.is_encrypted is False def test_partition_is_encrypted_lsblk(self, device_info): - lsblk = {'TYPE': 'part', 'FSTYPE': 'crypto_LUKS'} + lsblk = {'TYPE': 'part', 'FSTYPE': 'crypto_LUKS', 'PKNAME': 'sda'} device_info(lsblk=lsblk) disk = device.Device("/dev/sda") assert disk.is_encrypted is True def test_partition_is_not_encrypted_blkid(self, device_info): - lsblk = {'TYPE': 'part'} + lsblk = {'TYPE': 'part', 'PKNAME': 'sda'} blkid = {'TYPE': 'ceph data'} device_info(lsblk=lsblk, blkid=blkid) disk = device.Device("/dev/sda") assert disk.is_encrypted is False def test_partition_is_encrypted_blkid(self, device_info): - lsblk = {'TYPE': 'part'} + lsblk = {'TYPE': 'part', 'PKNAME': 'sda'} blkid = {'TYPE': 'crypto_LUKS'} device_info(lsblk=lsblk, blkid=blkid) disk = device.Device("/dev/sda") diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/util/device.py ceph-16.2.6/src/ceph-volume/ceph_volume/util/device.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/util/device.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/util/device.py 2021-09-16 14:27:19.000000000 +0000 @@ -1,13 +1,18 @@ # -*- coding: utf-8 -*- +import logging import os from functools import total_ordering -from ceph_volume import sys_info, process +from ceph_volume import sys_info from ceph_volume.api import lvm from ceph_volume.util import disk, system from ceph_volume.util.lsmdisk import LSMDisk from ceph_volume.util.constants import ceph_disk_guids + +logger = logging.getLogger(__name__) + + report_template = """ {dev:<25} {size:<12} {rot!s:<7} {available!s:<9} {model}""" @@ -320,6 +325,12 @@ return self.sys_api['size'] @property + def parent_device(self): + if 'PKNAME' in self.disk_api: + return '/dev/%s' % self.disk_api['PKNAME'] + return None + + @property def lvm_size(self): """ If this device was made into a PV it would lose 1GB in total size @@ -348,12 +359,7 @@ @property def has_bluestore_label(self): - out, err, ret = process.call([ - 'ceph-bluestore-tool', 'show-label', - '--dev', self.abspath], verbose_on_failure=False) - if ret: - return False - return True + return disk.has_bluestore_label(self.abspath) @property def is_mapper(self): @@ -476,8 +482,26 @@ rejected.append("Device type is not acceptable. It should be raw device or partition") if self.is_ceph_disk_member: rejected.append("Used by ceph-disk") - if self.has_bluestore_label: - rejected.append('Has BlueStore device label') + + try: + if self.has_bluestore_label: + rejected.append('Has BlueStore device label') + except OSError as e: + # likely failed to open the device. assuming it is BlueStore is the safest option + # so that a possibly-already-existing OSD doesn't get overwritten + logger.error('failed to determine if device {} is BlueStore. device should not be used to avoid false negatives. err: {}'.format(self.abspath, e)) + rejected.append('Failed to determine if device is BlueStore') + + if self.is_partition: + try: + if disk.has_bluestore_label(self.parent_device): + rejected.append('Parent has BlueStore device label') + except OSError as e: + # likely failed to open the device. assuming the parent is BlueStore is the safest + # option so that a possibly-already-existing OSD doesn't get overwritten + logger.error('failed to determine if partition {} (parent: {}) has a BlueStore parent. partition should not be used to avoid false negatives. err: {}'.format(self.abspath, self.parent_device, e)) + rejected.append('Failed to determine if parent device is BlueStore') + if self.has_gpt_headers: rejected.append('Has GPT headers') return rejected diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/util/disk.py ceph-16.2.6/src/ceph-volume/ceph_volume/util/disk.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/util/disk.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/util/disk.py 2021-09-16 14:27:19.000000000 +0000 @@ -134,14 +134,13 @@ :param device: A ``Device()`` object """ - parent_device = '/dev/%s' % device.disk_api['PKNAME'] udev_info = udevadm_property(device.abspath) partition_number = udev_info.get('ID_PART_ENTRY_NUMBER') if not partition_number: raise RuntimeError('Unable to detect the partition number for device: %s' % device.abspath) process.run( - ['parted', parent_device, '--script', '--', 'rm', partition_number] + ['parted', device.parent_device, '--script', '--', 'rm', partition_number] ) @@ -802,3 +801,17 @@ device_facts[diskname] = metadata return device_facts + +def has_bluestore_label(device_path): + isBluestore = False + bluestoreDiskSignature = 'bluestore block device' # 22 bytes long + + # throws OSError on failure + logger.info("opening device {} to check for BlueStore label".format(device_path)) + with open(device_path, "rb") as fd: + # read first 22 bytes looking for bluestore disk signature + signature = fd.read(22) + if signature.decode('ascii', 'replace') == bluestoreDiskSignature: + isBluestore = True + + return isBluestore diff -Nru ceph-16.2.5/src/ceph-volume/ceph_volume/util/system.py ceph-16.2.6/src/ceph-volume/ceph_volume/util/system.py --- ceph-16.2.5/src/ceph-volume/ceph_volume/util/system.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/ceph-volume/ceph_volume/util/system.py 2021-09-16 14:27:19.000000000 +0000 @@ -260,6 +260,7 @@ - tmpfs - devtmpfs + - /dev/root If ``devices`` is set to ``True`` the mapping will be a device-to-path(s), if ``paths`` is set to ``True`` then the mapping will be @@ -270,7 +271,7 @@ """ devices_mounted = {} paths_mounted = {} - do_not_skip = ['tmpfs', 'devtmpfs'] + do_not_skip = ['tmpfs', 'devtmpfs', '/dev/root'] default_to_devices = devices is False and paths is False with open(PROCDIR + '/mounts', 'rb') as mounts: diff -Nru ceph-16.2.5/src/client/Client.cc ceph-16.2.6/src/client/Client.cc --- ceph-16.2.5/src/client/Client.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/client/Client.cc 2021-09-16 14:27:19.000000000 +0000 @@ -1123,7 +1123,7 @@ /* * update MDS location cache for a single inode */ -void Client::update_dir_dist(Inode *in, DirStat *dst) +void Client::update_dir_dist(Inode *in, DirStat *dst, mds_rank_t from) { // auth ldout(cct, 20) << "got dirfrag map for " << in->ino << " frag " << dst->frag << " to mds " << dst->auth << dendl; @@ -1137,12 +1137,14 @@ _fragmap_remove_non_leaves(in); } - // replicated - in->dir_replicated = !dst->dist.empty(); - if (!dst->dist.empty()) - in->frag_repmap[dst->frag].assign(dst->dist.begin(), dst->dist.end()) ; - else - in->frag_repmap.erase(dst->frag); + // replicated, only update from auth mds reply + if (from == dst->auth) { + in->dir_replicated = !dst->dist.empty(); + if (!dst->dist.empty()) + in->frag_repmap[dst->frag].assign(dst->dist.begin(), dst->dist.end()) ; + else + in->frag_repmap.erase(dst->frag); + } } void Client::clear_dir_complete_and_ordered(Inode *diri, bool complete) @@ -1432,7 +1434,8 @@ if (reply->head.is_dentry) { diri = add_update_inode(&dirst, request->sent_stamp, session, request->perms); - update_dir_dist(diri, &dst); // dir stat info is attached to .. + mds_rank_t from_mds = mds_rank_t(reply->get_source().num()); + update_dir_dist(diri, &dst, from_mds); // dir stat info is attached to .. if (in) { Dir *dir = diri->open_dir(); @@ -6313,9 +6316,29 @@ } } +void Client::flush_mdlog_sync(Inode *in) +{ + if (in->unsafe_ops.empty()) { + return; + } + + std::set anchor; + for (auto &&p : in->unsafe_ops) { + anchor.emplace(p->mds); + } + if (in->auth_cap) { + anchor.emplace(in->auth_cap->session->mds_num); + } + + for (auto &rank : anchor) { + auto session = &mds_sessions.at(rank); + flush_mdlog(session); + } +} + void Client::flush_mdlog_sync() { - if (mds_requests.empty()) + if (mds_requests.empty()) return; for (auto &p : mds_sessions) { flush_mdlog(&p.second); @@ -10565,7 +10588,7 @@ } else ldout(cct, 10) << "no metadata needs to commit" << dendl; if (!syncdataonly && !in->unsafe_ops.empty()) { - flush_mdlog_sync(); + flush_mdlog_sync(in); MetaRequest *req = in->unsafe_ops.back(); ldout(cct, 15) << "waiting on unsafe requests, last tid " << req->get_tid() << dendl; diff -Nru ceph-16.2.5/src/client/Client.h ceph-16.2.6/src/client/Client.h --- ceph-16.2.5/src/client/Client.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/client/Client.h 2021-09-16 14:27:19.000000000 +0000 @@ -776,7 +776,7 @@ void unlock_fh_pos(Fh *f); // metadata cache - void update_dir_dist(Inode *in, DirStat *st); + void update_dir_dist(Inode *in, DirStat *st, mds_rank_t from); void clear_dir_complete_and_ordered(Inode *diri, bool complete); void insert_readdir_results(MetaRequest *request, MetaSession *session, Inode *diri); @@ -797,6 +797,7 @@ vinodeno_t map_faked_ino(ino_t ino); //notify the mds to flush the mdlog + void flush_mdlog_sync(Inode *in); void flush_mdlog_sync(); void flush_mdlog(MetaSession *session); diff -Nru ceph-16.2.5/src/cls/cmpomap/client.h ceph-16.2.6/src/cls/cmpomap/client.h --- ceph-16.2.5/src/cls/cmpomap/client.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cls/cmpomap/client.h 2021-09-16 14:27:19.000000000 +0000 @@ -26,7 +26,8 @@ /// process each of the omap value comparisons according to the same rules as /// cmpxattr(), and return -ECANCELED if a comparison is unsuccessful. for /// comparisons with Mode::U64, failure to decode an input value is reported -/// as -EINVAL, while failure to decode a stored value is reported as -EIO +/// as -EINVAL, an empty stored value is compared as 0, and failure to decode +/// a stored value is reported as -EIO [[nodiscard]] int cmp_vals(librados::ObjectReadOperation& op, Mode mode, Op comparison, ComparisonMap values, std::optional default_value); @@ -34,9 +35,9 @@ /// process each of the omap value comparisons according to the same rules as /// cmpxattr(). any key/value pairs that compare successfully are overwritten /// with the corresponding input value. for comparisons with Mode::U64, failure -/// to decode an input value is reported as -EINVAL. decode failure of a stored -/// value is treated as an unsuccessful comparison and is not reported as an -/// error +/// to decode an input value is reported as -EINVAL. an empty stored value is +/// compared as 0, while decode failure of a stored value is treated as an +/// unsuccessful comparison and is not reported as an error [[nodiscard]] int cmp_set_vals(librados::ObjectWriteOperation& writeop, Mode mode, Op comparison, ComparisonMap values, std::optional default_value); @@ -44,8 +45,9 @@ /// process each of the omap value comparisons according to the same rules as /// cmpxattr(). any key/value pairs that compare successfully are removed. for /// comparisons with Mode::U64, failure to decode an input value is reported as -/// -EINVAL. decode failure of a stored value is treated as an unsuccessful -/// comparison and is not reported as an error +/// -EINVAL. an empty stored value is compared as 0, while decode failure of a +/// stored value is treated as an unsuccessful comparison and is not reported +/// as an error [[nodiscard]] int cmp_rm_keys(librados::ObjectWriteOperation& writeop, Mode mode, Op comparison, ComparisonMap values); diff -Nru ceph-16.2.5/src/cls/cmpomap/server.cc ceph-16.2.6/src/cls/cmpomap/server.cc --- ceph-16.2.5/src/cls/cmpomap/server.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cls/cmpomap/server.cc 2021-09-16 14:27:19.000000000 +0000 @@ -37,17 +37,20 @@ static int compare_values_u64(Op op, uint64_t lhs, const bufferlist& value) { - try { - // decode existing value as rhs - uint64_t rhs; - auto p = value.cbegin(); - using ceph::decode; - decode(rhs, p); - return compare_values(op, lhs, rhs); - } catch (const buffer::error&) { - // failures to decode existing values are reported as EIO - return -EIO; + // empty values compare as 0 for backward compat + uint64_t rhs = 0; + if (value.length()) { + try { + // decode existing value as rhs + auto p = value.cbegin(); + using ceph::decode; + decode(rhs, p); + } catch (const buffer::error&) { + // failures to decode existing values are reported as EIO + return -EIO; + } } + return compare_values(op, lhs, rhs); } static int compare_value(Mode mode, Op op, const bufferlist& input, diff -Nru ceph-16.2.5/src/cls/rgw/cls_rgw.cc ceph-16.2.6/src/cls/rgw/cls_rgw.cc --- ceph-16.2.5/src/cls/rgw/cls_rgw.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cls/rgw/cls_rgw.cc 2021-09-16 14:27:19.000000000 +0000 @@ -501,6 +501,7 @@ bool has_delimiter = !op.delimiter.empty(); if (has_delimiter && + start_after_key > op.filter_prefix && boost::algorithm::ends_with(start_after_key, op.delimiter)) { // advance past all subdirectory entries if we start after a // subdirectory @@ -1195,6 +1196,7 @@ public: BIVerObjEntry(cls_method_context_t& _hctx, const cls_rgw_obj_key& _key) : hctx(_hctx), key(_key), initialized(false) { + // empty } int init(bool check_delete_marker = true) { @@ -1532,11 +1534,20 @@ return -EINVAL; } - BIVerObjEntry obj(hctx, op.key); - BIOLHEntry olh(hctx, op.key); - /* read instance entry */ + BIVerObjEntry obj(hctx, op.key); int ret = obj.init(op.delete_marker); + + /* NOTE: When a delete is issued, a key instance is always provided, + * either the one for which the delete is requested or a new random + * one when no instance is specified. So we need to see which of + * these two cases we're dealing with. The variable `existed` will + * be true if the instance was specified and false if it was + * randomly generated. It might have been cleaner if the instance + * were empty and randomly generated here and returned in the reply, + * as that would better allow a typo in the instance id. This code + * should be audited and possibly cleaned up. */ + bool existed = (ret == 0); if (ret == -ENOENT && op.delete_marker) { ret = 0; @@ -1545,6 +1556,28 @@ return ret; } + BIOLHEntry olh(hctx, op.key); + bool olh_read_attempt = false; + bool olh_found = false; + if (!existed && op.delete_marker) { + /* read olh */ + ret = olh.init(&olh_found); + if (ret < 0) { + return ret; + } + olh_read_attempt = true; + + // if we're deleting (i.e., adding a delete marker, and the OLH + // indicates it already refers to a delete marker, error out) + if (olh_found && olh.get_entry().delete_marker) { + CLS_LOG(10, + "%s: delete marker received for \"%s\" although OLH" + " already refers to a delete marker\n", + __func__, escape_str(op.key.to_string()).c_str()); + return -ENOENT; + } + } + if (existed && !real_clock::is_zero(op.unmod_since)) { timespec mtime = ceph::real_clock::to_timespec(obj.mtime()); timespec unmod = ceph::real_clock::to_timespec(op.unmod_since); @@ -1597,11 +1630,14 @@ } /* read olh */ - bool olh_found; - ret = olh.init(&olh_found); - if (ret < 0) { - return ret; + if (!olh_read_attempt) { // only read if we didn't attempt earlier + ret = olh.init(&olh_found); + if (ret < 0) { + return ret; + } + olh_read_attempt = true; } + const uint64_t prev_epoch = olh.get_epoch(); if (!olh.start_modify(op.olh_epoch)) { diff -Nru ceph-16.2.5/src/cls/rgw/cls_rgw_types.h ceph-16.2.6/src/cls/rgw/cls_rgw_types.h --- ceph-16.2.5/src/cls/rgw/cls_rgw_types.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/cls/rgw/cls_rgw_types.h 2021-09-16 14:27:19.000000000 +0000 @@ -1,13 +1,16 @@ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab -#ifndef CEPH_CLS_RGW_TYPES_H -#define CEPH_CLS_RGW_TYPES_H +#pragma once #include #include "common/ceph_time.h" #include "common/Formatter.h" +#undef FMT_HEADER_ONLY +#define FMT_HEADER_ONLY 1 +#include + #include "rgw/rgw_basic_types.h" #define CEPH_RGW_REMOVE 'r' @@ -340,6 +343,14 @@ cls_rgw_obj_key(const std::string &_name) : name(_name) {} cls_rgw_obj_key(const std::string& n, const std::string& i) : name(n), instance(i) {} + std::string to_string() const { + return fmt::format("{}({})", name, instance); + } + + bool empty() const { + return name.empty(); + } + void set(const std::string& _name) { name = _name; } @@ -348,6 +359,7 @@ return (name.compare(k.name) == 0) && (instance.compare(k.instance) == 0); } + bool operator<(const cls_rgw_obj_key& k) const { int r = name.compare(k.name); if (r == 0) { @@ -355,12 +367,16 @@ } return (r < 0); } + bool operator<=(const cls_rgw_obj_key& k) const { return !(k < *this); } - bool empty() const { - return name.empty(); + + std::ostream& operator<<(std::ostream& out) const { + out << to_string(); + return out; } + void encode(ceph::buffer::list &bl) const { ENCODE_START(1, 1, bl); encode(name, bl); @@ -1283,5 +1299,3 @@ void get_key(std::string *key) const; }; WRITE_CLASS_ENCODER(cls_rgw_reshard_entry) - -#endif diff -Nru ceph-16.2.5/src/CMakeLists.txt ceph-16.2.6/src/CMakeLists.txt --- ceph-16.2.5/src/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -304,12 +304,17 @@ include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/src/xxHash") include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/src/rapidjson/include") +option(WITH_FMT_HEADER_ONLY "use header-only version of fmt library" OFF) find_package(fmt 6.0.0 QUIET) if(fmt_FOUND) include_directories(SYSTEM "${fmt_INCLUDE_DIR}") else() message(STATUS "Could not find fmt, will build it") + set(old_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) + set(BUILD_SHARED_LIBS FALSE) add_subdirectory(fmt) + set(BUILD_SHARED_LIBS ${old_BUILD_SHARED_LIBS}) + unset(old_BUILD_SHARED_LIBS) include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/src/fmt/include") endif() @@ -360,6 +365,15 @@ add_subdirectory(crimson) endif() +function(compile_with_fmt target) + get_target_property(fmt_compile_definitions + fmt::fmt INTERFACE_COMPILE_DEFINITIONS) + if(fmt_compile_definitions) + target_compile_definitions(${target} PUBLIC + ${fmt_compile_definitions}) + endif() +endfunction() + set(libcommon_files ${CMAKE_BINARY_DIR}/src/include/ceph_ver.h ceph_ver.c @@ -396,6 +410,7 @@ set_source_files_properties(ceph_ver.c APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_BINARY_DIR}/src/include/ceph_ver.h) add_library(common-objs OBJECT ${libcommon_files}) +compile_with_fmt(common-objs) if(WITH_JAEGER) find_package(yaml-cpp 0.6.0) diff -Nru ceph-16.2.5/src/common/buffer.cc ceph-16.2.6/src/common/buffer.cc --- ceph-16.2.5/src/common/buffer.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/buffer.cc 2021-09-16 14:27:19.000000000 +0000 @@ -1254,8 +1254,12 @@ buffer::create_aligned(unaligned._len, align_memory))); had_to_rebuild = true; } - _buffers.insert_after(p_prev, *ptr_node::create(unaligned._buffers.front()).release()); - _num += 1; + if (unaligned.get_num_buffers()) { + _buffers.insert_after(p_prev, *ptr_node::create(unaligned._buffers.front()).release()); + _num += 1; + } else { + // a bufferlist containing only 0-length bptrs is rebuilt as empty + } ++p_prev; } return had_to_rebuild; diff -Nru ceph-16.2.5/src/common/CMakeLists.txt ceph-16.2.6/src/common/CMakeLists.txt --- ceph-16.2.5/src/common/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -177,6 +177,7 @@ "CEPH_LIBDIR=\"${CMAKE_INSTALL_FULL_LIBDIR}\"" "CEPH_PKGLIBDIR=\"${CEPH_INSTALL_FULL_PKGLIBDIR}\"" "CEPH_DATADIR=\"${CEPH_INSTALL_DATADIR}\"") +compile_with_fmt(common-common-objs) set(common_mountcephfs_srcs armor.c @@ -213,7 +214,7 @@ crc32c_aarch64.c) endif(HAVE_INTEL) -add_library(crc32 ${crc32_srcs}) +add_library(crc32 STATIC ${crc32_srcs}) if(HAVE_ARMV8_CRC) set_target_properties(crc32 PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} ${ARMV8_CRC_COMPILE_FLAGS}") diff -Nru ceph-16.2.5/src/common/Formatter.cc ceph-16.2.6/src/common/Formatter.cc --- ceph-16.2.5/src/common/Formatter.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/Formatter.cc 2021-09-16 14:27:19.000000000 +0000 @@ -19,6 +19,7 @@ #include "include/buffer.h" #include +#include #include #include diff -Nru ceph-16.2.5/src/common/ipaddr.cc ceph-16.2.6/src/common/ipaddr.cc --- ceph-16.2.5/src/common/ipaddr.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/ipaddr.cc 2021-09-16 14:27:19.000000000 +0000 @@ -5,7 +5,6 @@ #include #include #include -#include #if defined(__FreeBSD__) #include #include @@ -33,54 +32,23 @@ out->s_addr = addr->s_addr & mask; } - -static bool match_numa_node(const string& if_name, int numa_node) +bool matches_ipv4_in_subnet(const struct ifaddrs& addrs, + const struct sockaddr_in* net, + unsigned int prefix_len) { -#if defined(WITH_SEASTAR) || defined(_WIN32) - return true; -#else - int if_node = -1; - int r = get_iface_numa_node(if_name, &if_node); - if (r < 0) { + if (addrs.ifa_addr == nullptr) return false; - } - return if_node == numa_node; -#endif -} - -const struct ifaddrs *find_ipv4_in_subnet(const struct ifaddrs *addrs, - const struct sockaddr_in *net, - unsigned int prefix_len, - int numa_node) { - struct in_addr want, temp; + if (addrs.ifa_addr->sa_family != net->sin_family) + return false; + struct in_addr want; netmask_ipv4(&net->sin_addr, prefix_len, &want); - for (; addrs != NULL; addrs = addrs->ifa_next) { - - if (addrs->ifa_addr == NULL) - continue; - - if (strcmp(addrs->ifa_name, "lo") == 0 || boost::starts_with(addrs->ifa_name, "lo:")) - continue; - - if (numa_node >= 0 && !match_numa_node(addrs->ifa_name, numa_node)) - continue; - - if (addrs->ifa_addr->sa_family != net->sin_family) - continue; - - struct in_addr *cur = &((struct sockaddr_in*)addrs->ifa_addr)->sin_addr; - netmask_ipv4(cur, prefix_len, &temp); - - if (temp.s_addr == want.s_addr) { - return addrs; - } - } - - return NULL; + struct in_addr *cur = &((struct sockaddr_in*)addrs.ifa_addr)->sin_addr; + struct in_addr temp; + netmask_ipv4(cur, prefix_len, &temp); + return temp.s_addr == want.s_addr; } - void netmask_ipv6(const struct in6_addr *addr, unsigned int prefix_len, struct in6_addr *out) { @@ -94,59 +62,25 @@ memset(out->s6_addr+prefix_len/8+1, 0, 16-prefix_len/8-1); } +bool matches_ipv6_in_subnet(const struct ifaddrs& addrs, + const struct sockaddr_in6* net, + unsigned int prefix_len) +{ + if (addrs.ifa_addr == nullptr) + return false; -const struct ifaddrs *find_ipv6_in_subnet(const struct ifaddrs *addrs, - const struct sockaddr_in6 *net, - unsigned int prefix_len, - int numa_node) { - struct in6_addr want, temp; - + if (addrs.ifa_addr->sa_family != net->sin6_family) + return false; + struct in6_addr want; netmask_ipv6(&net->sin6_addr, prefix_len, &want); - for (; addrs != NULL; addrs = addrs->ifa_next) { - - if (addrs->ifa_addr == NULL) - continue; - - if (strcmp(addrs->ifa_name, "lo") == 0 || boost::starts_with(addrs->ifa_name, "lo:")) - continue; - - if (numa_node >= 0 && !match_numa_node(addrs->ifa_name, numa_node)) - continue; - - if (addrs->ifa_addr->sa_family != net->sin6_family) - continue; - - struct in6_addr *cur = &((struct sockaddr_in6*)addrs->ifa_addr)->sin6_addr; - if (IN6_IS_ADDR_LINKLOCAL(cur)) - continue; - netmask_ipv6(cur, prefix_len, &temp); - - if (IN6_ARE_ADDR_EQUAL(&temp, &want)) - return addrs; - } - - return NULL; -} - - -const struct ifaddrs *find_ip_in_subnet(const struct ifaddrs *addrs, - const struct sockaddr *net, - unsigned int prefix_len, - int numa_node) { - switch (net->sa_family) { - case AF_INET: - return find_ipv4_in_subnet(addrs, (struct sockaddr_in*)net, prefix_len, - numa_node); - - case AF_INET6: - return find_ipv6_in_subnet(addrs, (struct sockaddr_in6*)net, prefix_len, - numa_node); - } - - return NULL; + struct in6_addr temp; + struct in6_addr *cur = &((struct sockaddr_in6*)addrs.ifa_addr)->sin6_addr; + if (IN6_IS_ADDR_LINKLOCAL(cur)) + return false; + netmask_ipv6(cur, prefix_len, &temp); + return IN6_ARE_ADDR_EQUAL(&temp, &want); } - bool parse_network(const char *s, struct sockaddr_storage *network, unsigned int *prefix_len) { char *slash = strchr((char*)s, '/'); if (!slash) { diff -Nru ceph-16.2.5/src/common/legacy_config_opts.h ceph-16.2.6/src/common/legacy_config_opts.h --- ceph-16.2.5/src/common/legacy_config_opts.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/legacy_config_opts.h 2021-09-16 14:27:19.000000000 +0000 @@ -1445,7 +1445,6 @@ OPTION(rgw_data_log_obj_prefix, OPT_STR) // OPTION(rgw_bucket_quota_ttl, OPT_INT) // time for cached bucket stats to be cached within rgw instance -OPTION(rgw_bucket_quota_soft_threshold, OPT_DOUBLE) // threshold from which we don't rely on cached info for quota decisions OPTION(rgw_bucket_quota_cache_size, OPT_INT) // number of entries in bucket quota cache OPTION(rgw_bucket_default_quota_max_objects, OPT_INT) // number of objects allowed OPTION(rgw_bucket_default_quota_max_size, OPT_LONGLONG) // Max size of object in bytes @@ -1509,6 +1508,10 @@ OPTION(rgw_crypt_vault_prefix, OPT_STR) // Optional URL prefix to Vault secret path OPTION(rgw_crypt_vault_secret_engine, OPT_STR) // kv, transit or other supported secret engines OPTION(rgw_crypt_vault_namespace, OPT_STR) // Vault Namespace (only availabe in Vault Enterprise Version) +OPTION(rgw_crypt_vault_verify_ssl, OPT_BOOL) // should we try to verify vault's ssl +OPTION(rgw_crypt_vault_ssl_cacert, OPT_STR) // optional ca certificate for accessing vault +OPTION(rgw_crypt_vault_ssl_clientcert, OPT_STR) // client certificate for accessing vault +OPTION(rgw_crypt_vault_ssl_clientkey, OPT_STR) // private key for client certificate OPTION(rgw_crypt_kmip_addr, OPT_STR) // kmip server address OPTION(rgw_crypt_kmip_ca_path, OPT_STR) // ca for kmip servers diff -Nru ceph-16.2.5/src/common/options.cc ceph-16.2.6/src/common/options.cc --- ceph-16.2.5/src/common/options.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/options.cc 2021-09-16 14:27:19.000000000 +0000 @@ -1153,6 +1153,11 @@ .set_description("Maximum threadpool size of AsyncMessenger") .add_see_also("ms_async_op_threads"), + Option("ms_async_reap_threshold", Option::TYPE_UINT, Option::LEVEL_DEV) + .set_default(5) + .set_min(1) + .set_description("number of deleted connections before we reap"), + Option("ms_async_rdma_device_name", Option::TYPE_STR, Option::LEVEL_ADVANCED) .set_default("") .set_description(""), @@ -2678,7 +2683,7 @@ .set_long_description("If this value is exceeded, the OSD will not read any new client data off of the network until memory is freed."), Option("osd_client_message_cap", Option::TYPE_UINT, Option::LEVEL_ADVANCED) - .set_default(0) + .set_default(256) .set_description("maximum number of in-flight client requests"), Option("osd_crush_update_weight_set", Option::TYPE_BOOL, Option::LEVEL_ADVANCED) @@ -6777,16 +6782,6 @@ .set_long_description( "Length of time for bucket stats to be cached within RGW instance."), - Option("rgw_bucket_quota_soft_threshold", Option::TYPE_FLOAT, Option::LEVEL_BASIC) - .set_default(0.95) - .set_description("RGW quota soft threshold") - .set_long_description( - "Threshold from which RGW doesn't rely on cached info for quota " - "decisions. This is done for higher accuracy of the quota mechanism at " - "cost of performance, when getting close to the quota limit. The value " - "configured here is the ratio between the data usage to the max usage " - "as specified by the quota."), - Option("rgw_bucket_quota_cache_size", Option::TYPE_INT, Option::LEVEL_ADVANCED) .set_default(10000) .set_description("RGW quota stats cache size") @@ -7175,6 +7170,22 @@ "rgw_crypt_vault_auth", "rgw_crypt_vault_addr"}), + Option("rgw_crypt_vault_verify_ssl", Option::TYPE_BOOL, Option::LEVEL_ADVANCED) + .set_default(true) + .set_description("Should RGW verify the vault server SSL certificate."), + + Option("rgw_crypt_vault_ssl_cacert", Option::TYPE_STR, Option::LEVEL_ADVANCED) + .set_default("") + .set_description("Path for custom ca certificate for accessing vault server"), + + Option("rgw_crypt_vault_ssl_clientcert", Option::TYPE_STR, Option::LEVEL_ADVANCED) + .set_default("") + .set_description("Path for customed client certificate for accessing vault server"), + + Option("rgw_crypt_vault_ssl_clientkey", Option::TYPE_STR, Option::LEVEL_ADVANCED) + .set_default("") + .set_description("Path for private key required for client cert"), + Option("rgw_crypt_kmip_addr", Option::TYPE_STR, Option::LEVEL_ADVANCED) .set_default("") .set_description("kmip server address"), diff -Nru ceph-16.2.5/src/common/pick_address.cc ceph-16.2.6/src/common/pick_address.cc --- ceph-16.2.5/src/common/pick_address.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/pick_address.cc 2021-09-16 14:27:19.000000000 +0000 @@ -15,10 +15,12 @@ #include "common/pick_address.h" #include +#include #include #include #include +#include #include #include "include/ipaddr.h" @@ -32,11 +34,116 @@ #include "common/errno.h" #include "common/numa.h" +#ifndef HAVE_IN_ADDR_T +typedef uint32_t in_addr_t; +#endif + +#ifndef IN_LOOPBACKNET +#define IN_LOOPBACKNET 127 +#endif + #define dout_subsys ceph_subsys_ using std::string; using std::vector; +namespace { + +bool matches_with_name(const ifaddrs& ifa, const std::string& if_name) +{ + return if_name.compare(ifa.ifa_name) == 0; +} + +static int is_loopback_addr(sockaddr* addr) +{ + if (addr->sa_family == AF_INET) { + const sockaddr_in* sin = (struct sockaddr_in *)(addr); + const in_addr_t net = ntohl(sin->sin_addr.s_addr) >> IN_CLASSA_NSHIFT; + return net == IN_LOOPBACKNET ? 1 : 0; + } else if (addr->sa_family == AF_INET6) { + sockaddr_in6* sin6 = (struct sockaddr_in6 *)(addr); + return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) ? 1 : 0; + } else { + return -1; + } +} + +static int grade_addr(const ifaddrs& ifa) +{ + if (ifa.ifa_addr == nullptr) { + return -1; + } + int score = 0; + if (ifa.ifa_flags & IFF_UP) { + score += 4; + } + switch (is_loopback_addr(ifa.ifa_addr)) { + case 0: + // prefer non-loopback addresses + score += 2; + break; + case 1: + score += 0; + break; + default: + score = -1; + break; + } + return score; +} + +bool matches_with_net(const ifaddrs& ifa, + const sockaddr* net, + unsigned int prefix_len, + unsigned ipv) +{ + switch (net->sa_family) { + case AF_INET: + if (ipv & CEPH_PICK_ADDRESS_IPV4) { + return matches_ipv4_in_subnet(ifa, (struct sockaddr_in*)net, prefix_len); + } + break; + case AF_INET6: + if (ipv & CEPH_PICK_ADDRESS_IPV6) { + return matches_ipv6_in_subnet(ifa, (struct sockaddr_in6*)net, prefix_len); + } + break; + } + return false; +} + +bool matches_with_net(CephContext *cct, + const ifaddrs& ifa, + const std::string& s, + unsigned ipv) +{ + struct sockaddr_storage net; + unsigned int prefix_len; + if (!parse_network(s.c_str(), &net, &prefix_len)) { + lderr(cct) << "unable to parse network: " << s << dendl; + exit(1); + } + return matches_with_net(ifa, (sockaddr*)&net, prefix_len, ipv); +} + +int grade_with_numa_node(const ifaddrs& ifa, int numa_node) +{ +#if defined(WITH_SEASTAR) || defined(_WIN32) + return 0; +#else + if (numa_node < 0) { + return 0; + } + int if_node = -1; + int r = get_iface_numa_node(ifa.ifa_name, &if_node); + if (r < 0) { + return 0; + } + return if_node == numa_node ? 1 : 0; +#endif +} +} + const struct sockaddr *find_ip_in_subnet_list( CephContext *cct, const struct ifaddrs *ifa, @@ -45,86 +152,41 @@ const std::string &interfaces, int numa_node) { - std::list nets; - get_str_list(networks, nets); - std::list ifs; - get_str_list(interfaces, ifs); - - // filter interfaces by name - const struct ifaddrs *filtered = nullptr; - if (ifs.empty()) { - filtered = ifa; - } else { - if (nets.empty()) { + const auto ifs = get_str_list(interfaces); + const auto nets = get_str_list(networks); + if (!ifs.empty() && nets.empty()) { lderr(cct) << "interface names specified but not network names" << dendl; exit(1); - } - const struct ifaddrs *t = ifa; - struct ifaddrs *head = 0; - while (t) { - bool match = false; - for (auto& i : ifs) { - if (strcmp(i.c_str(), t->ifa_name) == 0) { - match = true; - break; - } - } - if (match) { - struct ifaddrs *n = new ifaddrs; - memcpy(n, t, sizeof(*t)); - n->ifa_next = head; - head = n; - } - t = t->ifa_next; - } - if (!head) { - lderr(cct) << "no interfaces matching " << ifs << dendl; - exit(1); - } - filtered = head; } - struct sockaddr *r = nullptr; - for (auto& s : nets) { - struct sockaddr_storage net; - unsigned int prefix_len; - - if (!parse_network(s.c_str(), &net, &prefix_len)) { - lderr(cct) << "unable to parse network: " << s << dendl; - exit(1); - } - - switch (net.ss_family) { - case AF_INET: - if (!(ipv & CEPH_PICK_ADDRESS_IPV4)) { - continue; - } - break; - case AF_INET6: - if (!(ipv & CEPH_PICK_ADDRESS_IPV6)) { - continue; - } - break; - } - - const struct ifaddrs *found = find_ip_in_subnet( - filtered, - (struct sockaddr *) &net, prefix_len, numa_node); - if (found) { - r = found->ifa_addr; - break; + int best_score = 0; + const sockaddr* best_addr = nullptr; + for (const auto* addr = ifa; addr != nullptr; addr = addr->ifa_next) { + if (!ifs.empty() && + std::none_of(std::begin(ifs), std::end(ifs), + [&](const auto& if_name) { + return matches_with_name(*addr, if_name); + })) { + continue; + } + if (!nets.empty() && + std::none_of(std::begin(nets), std::end(nets), + [&](const auto& net) { + return matches_with_net(cct, *addr, net, ipv); + })) { + continue; + } + int score = grade_addr(*addr); + if (score < 0) { + continue; + } + score += grade_with_numa_node(*addr, numa_node); + if (score > best_score) { + best_score = score; + best_addr = addr->ifa_addr; } } - - if (filtered != ifa) { - while (filtered) { - struct ifaddrs *t = filtered->ifa_next; - delete filtered; - filtered = t; - } - } - - return r; + return best_addr; } #ifndef WITH_SEASTAR @@ -147,8 +209,8 @@ static void fill_in_one_address(CephContext *cct, const struct ifaddrs *ifa, - const string networks, - const string interfaces, + const string &networks, + const string &interfaces, const char *conf_var, int numa_node = -1) { @@ -193,8 +255,6 @@ void pick_addresses(CephContext *cct, int needs) { - struct ifaddrs *ifa; - int r = getifaddrs(&ifa); auto public_addr = cct->_conf.get_val("public_addr"); auto public_network = cct->_conf.get_val("public_network"); auto public_network_interface = @@ -204,33 +264,33 @@ auto cluster_network_interface = cct->_conf.get_val("cluster_network_interface"); + struct ifaddrs *ifa; + int r = getifaddrs(&ifa); if (r < 0) { string err = cpp_strerror(errno); lderr(cct) << "unable to fetch interfaces and addresses: " << err << dendl; exit(1); } - + auto free_ifa = make_scope_guard([ifa] { freeifaddrs(ifa); }); if ((needs & CEPH_PICK_ADDRESS_PUBLIC) && public_addr.is_blank_ip() && !public_network.empty()) { fill_in_one_address(cct, ifa, public_network, public_network_interface, - "public_addr"); + "public_addr"); } if ((needs & CEPH_PICK_ADDRESS_CLUSTER) && cluster_addr.is_blank_ip()) { if (!cluster_network.empty()) { fill_in_one_address(cct, ifa, cluster_network, cluster_network_interface, - "cluster_addr"); + "cluster_addr"); } else { if (!public_network.empty()) { lderr(cct) << "Public network was set, but cluster network was not set " << dendl; lderr(cct) << " Using public network also for cluster network" << dendl; fill_in_one_address(cct, ifa, public_network, public_network_interface, - "cluster_addr"); + "cluster_addr"); } } } - - freeifaddrs(ifa); } #endif // !WITH_SEASTAR @@ -238,13 +298,15 @@ CephContext *cct, const struct ifaddrs *ifa, unsigned ipv, - const string networks, - const string interfaces, + const string &networks, + const string &interfaces, entity_addrvec_t *addrs, int numa_node = -1) { - const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, ipv, networks, - interfaces, numa_node); + const struct sockaddr *found = find_ip_in_subnet_list(cct, ifa, ipv, + networks, + interfaces, + numa_node); if (!found) { std::string ip_type = ""; if ((ipv & CEPH_PICK_ADDRESS_IPV4) && (ipv & CEPH_PICK_ADDRESS_IPV6)) { @@ -358,33 +420,29 @@ !networks.empty()) { int ipv4_r = !(ipv & CEPH_PICK_ADDRESS_IPV4) ? 0 : -1; int ipv6_r = !(ipv & CEPH_PICK_ADDRESS_IPV6) ? 0 : -1; - // first try on preferred numa node (if >= 0), then anywhere. - while (true) { - // note: pass in ipv to filter the matching addresses - if ((ipv & CEPH_PICK_ADDRESS_IPV4) && - (flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { - ipv4_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, - networks, interfaces, addrs, - preferred_numa_node); - } - if (ipv & CEPH_PICK_ADDRESS_IPV6) { - ipv6_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV6, - networks, interfaces, addrs, - preferred_numa_node); - } - if ((ipv & CEPH_PICK_ADDRESS_IPV4) && - !(flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { - ipv4_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, - networks, interfaces, addrs, - preferred_numa_node); - } - if (ipv4_r >= 0 && ipv6_r >= 0) { - break; - } - if (preferred_numa_node < 0) { - return ipv4_r >= 0 && ipv6_r >= 0 ? 0 : -1; - } - preferred_numa_node = -1; // try any numa node + // note: pass in ipv to filter the matching addresses + if ((ipv & CEPH_PICK_ADDRESS_IPV4) && + (flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { + ipv4_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, + networks, interfaces, + addrs, + preferred_numa_node); + } + if (ipv & CEPH_PICK_ADDRESS_IPV6) { + ipv6_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV6, + networks, interfaces, + addrs, + preferred_numa_node); + } + if ((ipv & CEPH_PICK_ADDRESS_IPV4) && + !(flags & CEPH_PICK_ADDRESS_PREFER_IPV4)) { + ipv4_r = fill_in_one_address(cct, ifa, CEPH_PICK_ADDRESS_IPV4, + networks, interfaces, + addrs, + preferred_numa_node); + } + if (ipv4_r < 0 || ipv6_r < 0) { + return -1; } } @@ -467,20 +525,15 @@ lderr(cct) << "unable to fetch interfaces and addresses: " << err << dendl; return {}; } - + auto free_ifa = make_scope_guard([ifa] { freeifaddrs(ifa); }); const unsigned int prefix_len = std::max(sizeof(in_addr::s_addr), sizeof(in6_addr::s6_addr)) * CHAR_BIT; - const struct ifaddrs *found = find_ip_in_subnet( - ifa, - (const struct sockaddr *) &network, prefix_len); - - std::string result; - if (found) { - result = found->ifa_name; + for (auto addr = ifa; addr != nullptr; addr = addr->ifa_next) { + if (matches_with_net(*ifa, (const struct sockaddr *) &network, prefix_len, + CEPH_PICK_ADDRESS_IPV4 | CEPH_PICK_ADDRESS_IPV6)) { + return addr->ifa_name; + } } - - freeifaddrs(ifa); - - return result; + return {}; } @@ -492,8 +545,8 @@ lderr(cct) << "unable to fetch interfaces and addresses: " << cpp_strerror(errno) << dendl; exit(1); } + auto free_ifa = make_scope_guard([ifa] { freeifaddrs(ifa); }); - bool found = false; for (struct ifaddrs *addrs = ifa; addrs != nullptr; addrs = addrs->ifa_next) { if (addrs->ifa_addr) { entity_addr_t a; @@ -501,16 +554,12 @@ for (auto& p : ls) { if (a.is_same_host(p)) { *match = p; - found = true; - goto out; + return true; } } } } - - out: - freeifaddrs(ifa); - return found; + return false; } int get_iface_numa_node( diff -Nru ceph-16.2.5/src/common/pick_address.h ceph-16.2.6/src/common/pick_address.h --- ceph-16.2.5/src/common/pick_address.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/pick_address.h 2021-09-16 14:27:19.000000000 +0000 @@ -68,6 +68,20 @@ */ bool have_local_addr(CephContext *cct, const std::list& ls, entity_addr_t *match); +/** + * filter the addresses in @c ifa with specified interfaces, networks and IPv + * + * @param cct + * @param ifa a list of network interface addresses to be filtered + * @param ipv bitmask of CEPH_PICK_ADDRESS_IPV4 and CEPH_PICK_ADDRESS_IPV6. + * it is used to filter the @c networks + * @param networks a comma separated list of networks as the allow list. only + * the addresses in the specified networks are allowed. all addresses + * are accepted if it is empty. + * @param interfaces a comma separated list of interfaces for the allow list. + * all addresses are accepted if it is empty + * @param exclude_lo_iface filter out network interface named "lo" + */ const struct sockaddr *find_ip_in_subnet_list( CephContext *cct, const struct ifaddrs *ifa, diff -Nru ceph-16.2.5/src/common/subsys.h ceph-16.2.6/src/common/subsys.h --- ceph-16.2.5/src/common/subsys.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/common/subsys.h 2021-09-16 14:27:19.000000000 +0000 @@ -74,7 +74,7 @@ SUBSYS(leveldb, 4, 5) SUBSYS(memdb, 4, 5) SUBSYS(fuse, 1, 5) -SUBSYS(mgr, 1, 5) +SUBSYS(mgr, 2, 5) SUBSYS(mgrc, 1, 5) SUBSYS(dpdk, 1, 5) SUBSYS(eventtrace, 1, 5) diff -Nru ceph-16.2.5/src/compressor/snappy/SnappyCompressor.h ceph-16.2.6/src/compressor/snappy/SnappyCompressor.h --- ceph-16.2.5/src/compressor/snappy/SnappyCompressor.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/compressor/snappy/SnappyCompressor.h 2021-09-16 14:27:19.000000000 +0000 @@ -97,8 +97,8 @@ if (qat_enabled) return qat_accel.decompress(p, compressed_len, dst, compressor_message); #endif - snappy::uint32 res_len = 0; BufferlistSource source_1(p, compressed_len); + uint32_t res_len = 0; if (!snappy::GetUncompressedLength(&source_1, &res_len)) { return -1; } diff -Nru ceph-16.2.5/src/.git_version ceph-16.2.6/src/.git_version --- ceph-16.2.5/src/.git_version 2021-07-08 14:06:43.000000000 +0000 +++ ceph-16.2.6/src/.git_version 2021-09-16 14:29:55.000000000 +0000 @@ -1,2 +1,2 @@ -0883bdea7337b95e4b611c768c0279868462204a -16.2.5 +ee28fb57e47e9f88813e24bbf4c14496ca299d31 +16.2.6 diff -Nru ceph-16.2.5/src/include/cephfs/metrics/Types.h ceph-16.2.6/src/include/cephfs/metrics/Types.h --- ceph-16.2.5/src/include/cephfs/metrics/Types.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/include/cephfs/metrics/Types.h 2021-09-16 14:27:19.000000000 +0000 @@ -60,16 +60,31 @@ return os; } -struct CapInfoPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_CAP_INFO; +struct ClientMetricPayloadBase { + ClientMetricPayloadBase(ClientMetricType type) : metric_type(type) {} + ClientMetricType get_type() const { + return metric_type; + } + + void print_type(ostream *out) const { + *out << metric_type; + } + + private: + ClientMetricType metric_type; +}; + +struct CapInfoPayload : public ClientMetricPayloadBase { uint64_t cap_hits = 0; uint64_t cap_misses = 0; uint64_t nr_caps = 0; - CapInfoPayload() { } + CapInfoPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_CAP_INFO) { } CapInfoPayload(uint64_t cap_hits, uint64_t cap_misses, uint64_t nr_caps) - : cap_hits(cap_hits), cap_misses(cap_misses), nr_caps(nr_caps) { + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_CAP_INFO), + cap_hits(cap_hits), cap_misses(cap_misses), nr_caps(nr_caps) { } void encode(bufferlist &bl) const { @@ -103,14 +118,13 @@ } }; -struct ReadLatencyPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_READ_LATENCY; - +struct ReadLatencyPayload : public ClientMetricPayloadBase { utime_t lat; - ReadLatencyPayload() { } + ReadLatencyPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_READ_LATENCY) { } ReadLatencyPayload(utime_t lat) - : lat(lat) { + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_READ_LATENCY), lat(lat) { } void encode(bufferlist &bl) const { @@ -136,14 +150,13 @@ } }; -struct WriteLatencyPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_WRITE_LATENCY; - +struct WriteLatencyPayload : public ClientMetricPayloadBase { utime_t lat; - WriteLatencyPayload() { } + WriteLatencyPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_WRITE_LATENCY) { } WriteLatencyPayload(utime_t lat) - : lat(lat) { + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_WRITE_LATENCY), lat(lat) { } void encode(bufferlist &bl) const { @@ -169,14 +182,13 @@ } }; -struct MetadataLatencyPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_METADATA_LATENCY; - +struct MetadataLatencyPayload : public ClientMetricPayloadBase { utime_t lat; - MetadataLatencyPayload() { } + MetadataLatencyPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_METADATA_LATENCY) { } MetadataLatencyPayload(utime_t lat) - : lat(lat) { + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_METADATA_LATENCY), lat(lat) { } void encode(bufferlist &bl) const { @@ -202,17 +214,16 @@ } }; -struct DentryLeasePayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_DENTRY_LEASE; - +struct DentryLeasePayload : public ClientMetricPayloadBase { uint64_t dlease_hits = 0; uint64_t dlease_misses = 0; uint64_t nr_dentries = 0; - DentryLeasePayload() { } + DentryLeasePayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_DENTRY_LEASE) { } DentryLeasePayload(uint64_t dlease_hits, uint64_t dlease_misses, uint64_t nr_dentries) - : dlease_hits(dlease_hits), dlease_misses(dlease_misses), nr_dentries(nr_dentries) { - } + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_DENTRY_LEASE), + dlease_hits(dlease_hits), dlease_misses(dlease_misses), nr_dentries(nr_dentries) { } void encode(bufferlist &bl) const { using ceph::encode; @@ -245,16 +256,15 @@ } }; -struct OpenedFilesPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_OPENED_FILES; - +struct OpenedFilesPayload : public ClientMetricPayloadBase { uint64_t opened_files = 0; uint64_t total_inodes = 0; - OpenedFilesPayload() { } + OpenedFilesPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_OPENED_FILES) { } OpenedFilesPayload(uint64_t opened_files, uint64_t total_inodes) - : opened_files(opened_files), total_inodes(total_inodes) { - } + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_OPENED_FILES), + opened_files(opened_files), total_inodes(total_inodes) { } void encode(bufferlist &bl) const { using ceph::encode; @@ -283,16 +293,15 @@ } }; -struct PinnedIcapsPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_PINNED_ICAPS; - +struct PinnedIcapsPayload : public ClientMetricPayloadBase { uint64_t pinned_icaps = 0; uint64_t total_inodes = 0; - PinnedIcapsPayload() { } + PinnedIcapsPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_PINNED_ICAPS) { } PinnedIcapsPayload(uint64_t pinned_icaps, uint64_t total_inodes) - : pinned_icaps(pinned_icaps), total_inodes(total_inodes) { - } + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_PINNED_ICAPS), + pinned_icaps(pinned_icaps), total_inodes(total_inodes) { } void encode(bufferlist &bl) const { using ceph::encode; @@ -321,16 +330,15 @@ } }; -struct OpenedInodesPayload { - static const ClientMetricType METRIC_TYPE = ClientMetricType::CLIENT_METRIC_TYPE_OPENED_INODES; - +struct OpenedInodesPayload : public ClientMetricPayloadBase { uint64_t opened_inodes = 0; uint64_t total_inodes = 0; - OpenedInodesPayload() { } + OpenedInodesPayload() + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_OPENED_INODES) { } OpenedInodesPayload(uint64_t opened_inodes, uint64_t total_inodes) - : opened_inodes(opened_inodes), total_inodes(total_inodes) { - } + : ClientMetricPayloadBase(ClientMetricType::CLIENT_METRIC_TYPE_OPENED_INODES), + opened_inodes(opened_inodes), total_inodes(total_inodes) { } void encode(bufferlist &bl) const { using ceph::encode; @@ -359,10 +367,11 @@ } }; -struct UnknownPayload { - static const ClientMetricType METRIC_TYPE = static_cast(-1); - - UnknownPayload() { } +struct UnknownPayload : public ClientMetricPayloadBase { + UnknownPayload() + : ClientMetricPayloadBase(static_cast(-1)) { } + UnknownPayload(ClientMetricType metric_type) + : ClientMetricPayloadBase(metric_type) { } void encode(bufferlist &bl) const { } @@ -406,7 +415,7 @@ template inline void operator()(const ClientMetricPayload &payload) const { using ceph::encode; - encode(static_cast(ClientMetricPayload::METRIC_TYPE), m_bl); + encode(static_cast(payload.get_type()), m_bl); payload.encode(m_bl); } @@ -436,8 +445,7 @@ template inline void operator()(const ClientMetricPayload &payload) const { - ClientMetricType metric_type = ClientMetricPayload::METRIC_TYPE; - m_formatter->dump_string("client_metric_type", stringify(metric_type)); + m_formatter->dump_string("client_metric_type", stringify(payload.get_type())); payload.dump(m_formatter); } @@ -452,8 +460,9 @@ template inline void operator()(const ClientMetricPayload &payload) const { - ClientMetricType metric_type = ClientMetricPayload::METRIC_TYPE; - *_out << "[client_metric_type: " << metric_type; + *_out << "[client_metric_type: "; + payload.print_type(_out); + *_out << " "; payload.print(_out); *_out << "]"; } @@ -498,7 +507,7 @@ payload = OpenedInodesPayload(); break; default: - payload = UnknownPayload(); + payload = UnknownPayload(static_cast(metric_type)); break; } diff -Nru ceph-16.2.5/src/include/CompatSet.h ceph-16.2.6/src/include/CompatSet.h --- ceph-16.2.5/src/include/CompatSet.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/include/CompatSet.h 2021-09-16 14:27:19.000000000 +0000 @@ -156,7 +156,7 @@ * -1: This CompatSet is missing at least one feature * described in the other. It may still have more features, though. */ - int compare(const CompatSet& other) { + int compare(const CompatSet& other) const { if ((other.compat.mask == compat.mask) && (other.ro_compat.mask == ro_compat.mask) && (other.incompat.mask == incompat.mask)) return 0; @@ -172,7 +172,7 @@ /* Get the features supported by other CompatSet but not this one, * as a CompatSet. */ - CompatSet unsupported(CompatSet& other) { + CompatSet unsupported(const CompatSet& other) const { CompatSet diff; uint64_t other_compat = ((other.compat.mask ^ compat.mask) & other.compat.mask); @@ -183,13 +183,13 @@ for (int id = 1; id < 64; ++id) { uint64_t mask = (uint64_t)1 << id; if (mask & other_compat) { - diff.compat.insert( Feature(id, other.compat.names[id])); + diff.compat.insert( Feature(id, other.compat.names.at(id))); } if (mask & other_ro_compat) { - diff.ro_compat.insert(Feature(id, other.ro_compat.names[id])); + diff.ro_compat.insert(Feature(id, other.ro_compat.names.at(id))); } if (mask & other_incompat) { - diff.incompat.insert( Feature(id, other.incompat.names[id])); + diff.incompat.insert( Feature(id, other.incompat.names.at(id))); } } return diff; @@ -222,6 +222,13 @@ return true; } + std::ostream& printlite(std::ostream& o) const { + o << "{c=[" << std::hex << compat.mask << "]"; + o << ",r=[" << std::hex << ro_compat.mask << "]"; + o << ",i=[" << std::hex << incompat.mask << "]}"; + return o; + } + void encode(ceph::buffer::list& bl) const { compat.encode(bl); ro_compat.encode(bl); @@ -257,6 +264,11 @@ }; WRITE_CLASS_ENCODER(CompatSet) +inline std::ostream& operator<<(std::ostream& out, const CompatSet::Feature& f) +{ + return out << "F(" << f.id << ", \"" << f.name << "\")"; +} + inline std::ostream& operator<<(std::ostream& out, const CompatSet::FeatureSet& fs) { return out << fs.names; diff -Nru ceph-16.2.5/src/include/config-h.in.cmake ceph-16.2.6/src/include/config-h.in.cmake --- ceph-16.2.5/src/include/config-h.in.cmake 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/include/config-h.in.cmake 2021-09-16 14:27:19.000000000 +0000 @@ -63,6 +63,9 @@ /* Define to 1 if the system has the type `__u8'. */ #cmakedefine HAVE___U8 1 +/* Define if the system has the type `in_addr_t' */ +#cmakedefine HAVE_IN_ADDR_T + /* Define if you have res_nquery */ #cmakedefine HAVE_RES_NQUERY diff -Nru ceph-16.2.5/src/include/denc.h ceph-16.2.6/src/include/denc.h --- ceph-16.2.5/src/include/denc.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/include/denc.h 2021-09-16 14:27:19.000000000 +0000 @@ -39,6 +39,7 @@ #include #include +#include "include/compat.h" #include "include/intarith.h" #include "include/int_types.h" #include "include/scope_guard.h" diff -Nru ceph-16.2.5/src/include/ipaddr.h ceph-16.2.6/src/include/ipaddr.h --- ceph-16.2.5/src/include/ipaddr.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/include/ipaddr.h 2021-09-16 14:27:19.000000000 +0000 @@ -4,15 +4,14 @@ class entity_addr_t; /* - * Find an IP address that is in the wanted subnet. - * - * If there are multiple matches, the first one is returned; this order - * is system-dependent and should not be relied on. + * Check if an IP address that is in the wanted subnet. */ -const struct ifaddrs *find_ip_in_subnet(const struct ifaddrs *addrs, - const struct sockaddr *net, - unsigned int prefix_len, - int numa_node = -1); +bool matches_ipv4_in_subnet(const struct ifaddrs& addrs, + const struct sockaddr_in* net, + unsigned int prefix_len); +bool matches_ipv6_in_subnet(const struct ifaddrs& addrs, + const struct sockaddr_in6* net, + unsigned int prefix_len); /* * Validate and parse IPv4 or IPv6 network diff -Nru ceph-16.2.5/src/krbd.cc ceph-16.2.6/src/krbd.cc --- ceph-16.2.5/src/krbd.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/krbd.cc 2021-09-16 14:27:19.000000000 +0000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -612,6 +613,13 @@ return 0; } +// wrap any of * ? [ between square brackets +static std::string escape_glob(const std::string& s) +{ + std::regex glob_meta("([*?[])"); + return std::regex_replace(s, glob_meta, "[$1]"); +} + static int __enumerate_devices(struct udev *udev, const krbd_spec& spec, bool match_nspace, udev_enumerate_uptr *penm) { @@ -628,13 +636,13 @@ return r; r = udev_enumerate_add_match_sysattr(enm.get(), "pool", - spec.pool_name.c_str()); + escape_glob(spec.pool_name).c_str()); if (r < 0) return r; if (match_nspace) { r = udev_enumerate_add_match_sysattr(enm.get(), "pool_ns", - spec.nspace_name.c_str()); + escape_glob(spec.nspace_name).c_str()); } else { /* * Match _only_ devices that don't have pool_ns attribute. @@ -646,12 +654,12 @@ return r; r = udev_enumerate_add_match_sysattr(enm.get(), "name", - spec.image_name.c_str()); + escape_glob(spec.image_name).c_str()); if (r < 0) return r; r = udev_enumerate_add_match_sysattr(enm.get(), "current_snap", - spec.snap_name.c_str()); + escape_glob(spec.snap_name).c_str()); if (r < 0) return r; diff -Nru ceph-16.2.5/src/kv/RocksDBStore.cc ceph-16.2.6/src/kv/RocksDBStore.cc --- ceph-16.2.5/src/kv/RocksDBStore.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/kv/RocksDBStore.cc 2021-09-16 14:27:19.000000000 +0000 @@ -774,23 +774,12 @@ // copy default CF settings, block cache, merge operators as // the base for new CF rocksdb::ColumnFamilyOptions cf_opt(opt); - // user input options will override the base options - std::unordered_map column_opts_map; - std::string block_cache_opts; - int r = extract_block_cache_options(p.options, &column_opts_map, &block_cache_opts); - if (r != 0) { - derr << __func__ << " failed to parse options; column family=" << p.name << - " options=" << p.options << dendl; - return -EINVAL; - } rocksdb::Status status; - status = rocksdb::GetColumnFamilyOptionsFromMap(cf_opt, column_opts_map, &cf_opt); - if (!status.ok()) { - derr << __func__ << " invalid db options; column family=" - << p.name << " options=" << p.options << dendl; - return -EINVAL; + // apply options to column family + int r = update_column_family_options(p.name, p.options, &cf_opt); + if (r != 0) { + return r; } - install_cf_mergeop(p.name, &cf_opt); for (size_t idx = 0; idx < p.shard_cnt; idx++) { std::string cf_name; if (p.shard_cnt == 1) @@ -846,34 +835,153 @@ } return 0; } + // linking to rocksdb function defined in options_helper.cc // it can parse nested params like "nested_opt={opt1=1;opt2=2}" - extern rocksdb::Status rocksdb::StringToMap(const std::string& opts_str, std::unordered_map* opts_map); -int RocksDBStore::extract_block_cache_options(const std::string& opts_str, - std::unordered_map* column_opts_map, +// Splits column family options from single string into name->value column_opts_map. +// The split is done using RocksDB parser that understands "{" and "}", so it +// properly extracts compound options. +// If non-RocksDB option "block_cache" is defined it is extracted to block_cache_opt. +int RocksDBStore::split_column_family_options(const std::string& options, + std::unordered_map* opt_map, std::string* block_cache_opt) { - dout(5) << __func__ << " opts_str=" << opts_str << dendl; - rocksdb::Status status = rocksdb::StringToMap(opts_str, column_opts_map); + dout(20) << __func__ << " options=" << options << dendl; + rocksdb::Status status = rocksdb::StringToMap(options, opt_map); if (!status.ok()) { - dout(5) << __func__ << " error '" << status.getState() << - "' while parsing options '" << opts_str << "'" << dendl; + dout(5) << __func__ << " error '" << status.getState() + << "' while parsing options '" << options << "'" << dendl; return -EINVAL; } - //extract "block_cache" option - if (auto it = column_opts_map->find("block_cache"); it != column_opts_map->end()) { + // if "block_cache" option exists, then move it to separate string + if (auto it = opt_map->find("block_cache"); it != opt_map->end()) { *block_cache_opt = it->second; - column_opts_map->erase(it); + opt_map->erase(it); } else { block_cache_opt->clear(); } return 0; } +// Updates column family options. +// Take options from more_options and apply them to cf_opt. +// Allowed options are exactly the same as allowed for column families in RocksDB. +// Ceph addition is "block_cache" option that is translated to block_cache and +// allows to specialize separate block cache for O column family. +// +// base_name - name of column without shard suffix: "-"+number +// options - additional options to apply +// cf_opt - column family options to update +int RocksDBStore::update_column_family_options(const std::string& base_name, + const std::string& more_options, + rocksdb::ColumnFamilyOptions* cf_opt) +{ + std::unordered_map options_map; + std::string block_cache_opt; + rocksdb::Status status; + int r = split_column_family_options(more_options, &options_map, &block_cache_opt); + if (r != 0) { + dout(5) << __func__ << " failed to parse options; column family=" << base_name + << " options=" << more_options << dendl; + return r; + } + status = rocksdb::GetColumnFamilyOptionsFromMap(*cf_opt, options_map, cf_opt); + if (!status.ok()) { + dout(5) << __func__ << " invalid column family optionsp; column family=" + << base_name << " options=" << more_options << dendl; + dout(5) << __func__ << " RocksDB error='" << status.getState() << "'" << dendl; + return -EINVAL; + } + if (base_name != rocksdb::kDefaultColumnFamilyName) { + // default cf has its merge operator defined in load_rocksdb_options, should not override it + install_cf_mergeop(base_name, cf_opt); + } + if (!block_cache_opt.empty()) { + r = apply_block_cache_options(base_name, block_cache_opt, cf_opt); + if (r != 0) { + // apply_block_cache_options already does all necessary douts + return r; + } + } + return 0; +} +int RocksDBStore::apply_block_cache_options(const std::string& column_name, + const std::string& block_cache_opt, + rocksdb::ColumnFamilyOptions* cf_opt) +{ + rocksdb::Status status; + std::unordered_map cache_options_map; + status = rocksdb::StringToMap(block_cache_opt, &cache_options_map); + if (!status.ok()) { + dout(5) << __func__ << " invalid block cache options; column=" << column_name + << " options=" << block_cache_opt << dendl; + dout(5) << __func__ << " RocksDB error='" << status.getState() << "'" << dendl; + return -EINVAL; + } + bool require_new_block_cache = false; + std::string cache_type = cct->_conf->rocksdb_cache_type; + if (const auto it = cache_options_map.find("type"); it != cache_options_map.end()) { + cache_type = it->second; + cache_options_map.erase(it); + require_new_block_cache = true; + } + size_t cache_size = cct->_conf->rocksdb_cache_size; + if (auto it = cache_options_map.find("size"); it != cache_options_map.end()) { + std::string error; + cache_size = strict_iecstrtoll(it->second.c_str(), &error); + if (!error.empty()) { + dout(10) << __func__ << " invalid size: '" << it->second << "'" << dendl; + return -EINVAL; + } + cache_options_map.erase(it); + require_new_block_cache = true; + } + double high_pri_pool_ratio = 0.0; + if (auto it = cache_options_map.find("high_ratio"); it != cache_options_map.end()) { + std::string error; + high_pri_pool_ratio = strict_strtod(it->second.c_str(), &error); + if (!error.empty()) { + dout(10) << __func__ << " invalid high_pri (float): '" << it->second << "'" << dendl; + return -EINVAL; + } + cache_options_map.erase(it); + require_new_block_cache = true; + } + + rocksdb::BlockBasedTableOptions column_bbt_opts; + status = GetBlockBasedTableOptionsFromMap(bbt_opts, cache_options_map, &column_bbt_opts); + if (!status.ok()) { + dout(5) << __func__ << " invalid block cache options; column=" << column_name + << " options=" << block_cache_opt << dendl; + dout(5) << __func__ << " RocksDB error='" << status.getState() << "'" << dendl; + return -EINVAL; + } + std::shared_ptr block_cache; + if (column_bbt_opts.no_block_cache) { + // clear all settings except no_block_cache + // rocksdb does not like then + column_bbt_opts = rocksdb::BlockBasedTableOptions(); + column_bbt_opts.no_block_cache = true; + } else { + if (require_new_block_cache) { + block_cache = create_block_cache(cache_type, cache_size, high_pri_pool_ratio); + if (!block_cache) { + dout(5) << __func__ << " failed to create block cache for params: " << block_cache_opt << dendl; + return -EINVAL; + } + } else { + block_cache = bbt_opts.block_cache; + } + } + column_bbt_opts.block_cache = block_cache; + cf_bbt_opts[column_name] = column_bbt_opts; + cf_opt->table_factory.reset(NewBlockBasedTableFactory(cf_bbt_opts[column_name])); + return 0; +} int RocksDBStore::verify_sharding(const rocksdb::Options& opt, std::vector& existing_cfs, @@ -908,6 +1016,7 @@ status = rocksdb::DB::ListColumnFamilies(rocksdb::DBOptions(opt), path, &rocksdb_cfs); if (!status.ok()) { + derr << __func__ << " unable to list column families: " << status.ToString() << dendl; return -EIO; } dout(5) << __func__ << " column families from rocksdb: " << rocksdb_cfs << dendl; @@ -927,89 +1036,9 @@ for (auto& column : stored_sharding_def) { rocksdb::ColumnFamilyOptions cf_opt(opt); - std::unordered_map options_map; - std::string block_cache_opt; - - int r = extract_block_cache_options(column.options, &options_map, &block_cache_opt); + int r = update_column_family_options(column.name, column.options, &cf_opt); if (r != 0) { - derr << __func__ << " failed to parse options; column family=" << column.name << - " options=" << column.options << dendl; - return -EINVAL; - } - status = rocksdb::GetColumnFamilyOptionsFromMap(cf_opt, options_map, &cf_opt); - if (!status.ok()) { - derr << __func__ << " invalid db column family options for CF '" - << column.name << "': " << column.options << dendl; - derr << __func__ << " error = '" << status.getState() << "'" << dendl; - return -EINVAL; - } - install_cf_mergeop(column.name, &cf_opt); - - if (!block_cache_opt.empty()) { - std::unordered_map cache_options_map; - status = rocksdb::StringToMap(block_cache_opt, &cache_options_map); - if (!status.ok()) { - derr << __func__ << " invalid block cache options; column=" << column.name << - " options=" << block_cache_opt << dendl; - derr << __func__ << " error = '" << status.getState() << "'" << dendl; - return -EINVAL; - } - bool require_new_block_cache = false; - std::string cache_type = cct->_conf->rocksdb_cache_type; - if (const auto it = cache_options_map.find("type"); it !=cache_options_map.end()) { - cache_type = it->second; - cache_options_map.erase(it); - require_new_block_cache = true; - } - size_t cache_size = cct->_conf->rocksdb_cache_size; - if (auto it = cache_options_map.find("size"); it !=cache_options_map.end()) { - std::string error; - cache_size = strict_iecstrtoll(it->second.c_str(), &error); - if (!error.empty()) { - derr << __func__ << " invalid size: '" << it->second << "'" << dendl; - } - cache_options_map.erase(it); - require_new_block_cache = true; - } - double high_pri_pool_ratio = 0.0; - if (auto it = cache_options_map.find("high_ratio"); it !=cache_options_map.end()) { - std::string error; - high_pri_pool_ratio = strict_strtod(it->second.c_str(), &error); - if (!error.empty()) { - derr << __func__ << " invalid high_pri (float): '" << it->second << "'" << dendl; - } - cache_options_map.erase(it); - require_new_block_cache = true; - } - - rocksdb::BlockBasedTableOptions column_bbt_opts; - status = GetBlockBasedTableOptionsFromMap(bbt_opts, cache_options_map, &column_bbt_opts); - if (!status.ok()) { - derr << __func__ << " invalid block cache options; column=" << column.name << - " options=" << block_cache_opt << dendl; - derr << __func__ << " error = '" << status.getState() << "'" << dendl; - return -EINVAL; - } - std::shared_ptr block_cache; - if (column_bbt_opts.no_block_cache) { - // clear all settings except no_block_cache - // rocksdb does not like then - column_bbt_opts = rocksdb::BlockBasedTableOptions(); - column_bbt_opts.no_block_cache = true; - } else { - if (require_new_block_cache) { - block_cache = create_block_cache(cache_type, cache_size, high_pri_pool_ratio); - if (!block_cache) { - dout(5) << __func__ << " failed to create block cache for params: " << block_cache_opt << dendl; - return -EINVAL; - } - } else { - block_cache = bbt_opts.block_cache; - } - } - column_bbt_opts.block_cache = block_cache; - cf_bbt_opts[column.name] = column_bbt_opts; - cf_opt.table_factory.reset(NewBlockBasedTableFactory(cf_bbt_opts[column.name])); + return r; } if (column.shard_cnt == 1) { emplace_cf(column, 0, column.name, cf_opt); @@ -3014,13 +3043,10 @@ break; } } - status = rocksdb::GetColumnFamilyOptionsFromString(cf_opt, options, &cf_opt); - if (!status.ok()) { - derr << __func__ << " failure parsing column options: " << options << dendl; - return -EINVAL; + int r = update_column_family_options(base_name, options, &cf_opt); + if (r != 0) { + return r; } - if (base_name != rocksdb::kDefaultColumnFamilyName) - install_cf_mergeop(base_name, &cf_opt); cfs_to_open.emplace_back(full_name, cf_opt); } @@ -3074,12 +3100,10 @@ break; } } - status = rocksdb::GetColumnFamilyOptionsFromString(cf_opt, options, &cf_opt); - if (!status.ok()) { - derr << __func__ << " failure parsing column options: " << options << dendl; - return -EINVAL; + int r = update_column_family_options(base_name, options, &cf_opt); + if (r != 0) { + return r; } - install_cf_mergeop(base_name, &cf_opt); rocksdb::ColumnFamilyHandle *cf; status = db->CreateColumnFamily(cf_opt, full_name, &cf); if (!status.ok()) { diff -Nru ceph-16.2.5/src/kv/RocksDBStore.h ceph-16.2.6/src/kv/RocksDBStore.h --- ceph-16.2.5/src/kv/RocksDBStore.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/kv/RocksDBStore.h 2021-09-16 14:27:19.000000000 +0000 @@ -151,9 +151,15 @@ std::vector& missing_cfs, std::vector >& missing_cfs_shard); std::shared_ptr create_block_cache(const std::string& cache_type, size_t cache_size, double cache_prio_high = 0.0); - int extract_block_cache_options(const std::string& opts_str, + int split_column_family_options(const std::string& opts_str, std::unordered_map* column_opts_map, std::string* block_cache_opt); + int apply_block_cache_options(const std::string& column_name, + const std::string& block_cache_opt, + rocksdb::ColumnFamilyOptions* cf_opt); + int update_column_family_options(const std::string& base_name, + const std::string& more_options, + rocksdb::ColumnFamilyOptions* cf_opt); // manage async compactions ceph::mutex compact_queue_lock = ceph::make_mutex("RocksDBStore::compact_thread_lock"); diff -Nru ceph-16.2.5/src/mds/Beacon.cc ceph-16.2.6/src/mds/Beacon.cc --- ceph-16.2.5/src/mds/Beacon.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/Beacon.cc 2021-09-16 14:27:19.000000000 +0000 @@ -41,7 +41,8 @@ Dispatcher(cct), beacon_interval(g_conf()->mds_beacon_interval), monc(monc), - name(name) + name(name), + compat(MDSMap::get_compat_set_all()) { } @@ -233,10 +234,8 @@ { ceph_assert(mdsmap.get_epoch() >= epoch); - if (mdsmap.get_epoch() != epoch) { + if (mdsmap.get_epoch() >= epoch) { epoch = mdsmap.get_epoch(); - compat = MDSMap::get_compat_set_default(); - compat.merge(mdsmap.compat); } } diff -Nru ceph-16.2.5/src/mds/CDir.cc ceph-16.2.6/src/mds/CDir.cc --- ceph-16.2.5/src/mds/CDir.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/CDir.cc 2021-09-16 14:27:19.000000000 +0000 @@ -28,6 +28,7 @@ #include "Locker.h" #include "MDLog.h" #include "LogSegment.h" +#include "MDBalancer.h" #include "common/bloom_filter.hpp" #include "include/Context.h" @@ -1577,6 +1578,8 @@ if (mdcache->mds->logger) mdcache->mds->logger->inc(l_mds_dir_fetch); + mdcache->mds->balancer->hit_dir(this, META_POP_FETCH); + std::set empty; _omap_fetch(NULL, empty); } @@ -1602,6 +1605,8 @@ auth_pin(this); if (mdcache->mds->logger) mdcache->mds->logger->inc(l_mds_dir_fetch); + mdcache->mds->balancer->hit_dir(this, META_POP_FETCH); + _omap_fetch(c, keys); } @@ -2552,6 +2557,8 @@ if (mdcache->mds->logger) mdcache->mds->logger->inc(l_mds_dir_commit); + mdcache->mds->balancer->hit_dir(this, META_POP_STORE); + _omap_commit(op_prio); } diff -Nru ceph-16.2.5/src/mds/FSMap.cc ceph-16.2.6/src/mds/FSMap.cc --- ceph-16.2.5/src/mds/FSMap.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/FSMap.cc 2021-09-16 14:27:19.000000000 +0000 @@ -131,7 +131,7 @@ f->dump_int("default_fscid", legacy_client_fscid); f->open_object_section("compat"); - compat.dump(f); + default_compat.dump(f); f->close_section(); f->open_object_section("feature_flags"); @@ -162,7 +162,7 @@ epoch = rhs.epoch; next_filesystem_id = rhs.next_filesystem_id; legacy_client_fscid = rhs.legacy_client_fscid; - compat = rhs.compat; + default_compat = rhs.default_compat; enable_multiple = rhs.enable_multiple; mds_roles = rhs.mds_roles; standby_daemons = rhs.standby_daemons; @@ -202,7 +202,7 @@ out << "e" << epoch << std::endl; out << "enable_multiple, ever_enabled_multiple: " << enable_multiple << "," << ever_enabled_multiple << std::endl; - out << "compat: " << compat << std::endl; + out << "default compat: " << default_compat << std::endl; out << "legacy client fscid: " << legacy_client_fscid << std::endl; out << " " << std::endl; @@ -449,7 +449,8 @@ } Filesystem::ref FSMap::create_filesystem(std::string_view name, - int64_t metadata_pool, int64_t data_pool, uint64_t features) + int64_t metadata_pool, int64_t data_pool, uint64_t features, + fs_cluster_id_t fscid) { auto fs = Filesystem::create(); fs->mds_map.epoch = epoch; @@ -457,14 +458,25 @@ fs->mds_map.data_pools.push_back(data_pool); fs->mds_map.metadata_pool = metadata_pool; fs->mds_map.cas_pool = -1; - fs->mds_map.compat = compat; + fs->mds_map.compat = default_compat; fs->mds_map.created = ceph_clock_now(); fs->mds_map.modified = ceph_clock_now(); fs->mds_map.enabled = true; - fs->fscid = next_filesystem_id++; - // ANONYMOUS is only for upgrades from legacy mdsmaps, we should - // have initialized next_filesystem_id such that it's never used here. - ceph_assert(fs->fscid != FS_CLUSTER_ID_ANONYMOUS); + if (fscid == FS_CLUSTER_ID_NONE) { + fs->fscid = next_filesystem_id++; + } else { + fs->fscid = fscid; + next_filesystem_id = std::max(fscid, (fs_cluster_id_t)next_filesystem_id) + 1; + } + + // File system's ID can be FS_CLUSTER_ID_ANONYMOUS if we're recovering + // a legacy file system by passing FS_CLUSTER_ID_ANONYMOUS as the desired + // file system ID + if (fscid != FS_CLUSTER_ID_ANONYMOUS) { + // ANONYMOUS is only for upgrades from legacy mdsmaps, we should + // have initialized next_filesystem_id such that it's never used here. + ceph_assert(fs->fscid != FS_CLUSTER_ID_ANONYMOUS); + } filesystems[fs->fscid] = fs; // Created first filesystem? Set it as the one @@ -512,7 +524,7 @@ new_fs->mds_map.metadata_pool = fs->mds_map.metadata_pool; new_fs->mds_map.cas_pool = fs->mds_map.cas_pool; new_fs->mds_map.fs_name = fs->mds_map.fs_name; - new_fs->mds_map.compat = compat; + new_fs->mds_map.compat = default_compat; new_fs->mds_map.created = ceph_clock_now(); new_fs->mds_map.modified = ceph_clock_now(); new_fs->mds_map.standby_count_wanted = fs->mds_map.standby_count_wanted; @@ -606,27 +618,13 @@ } } -void FSMap::update_compat(const CompatSet &c) -{ - // We could do something more complicated here to enable - // different filesystems to be served by different MDS versions, - // but this is a lot simpler because it doesn't require us to - // track the compat versions for standby daemons. - compat = c; - for (const auto &i : filesystems) { - MDSMap &mds_map = i.second->mds_map; - mds_map.compat = c; - mds_map.epoch = epoch; - } -} - void FSMap::encode(bufferlist& bl, uint64_t features) const { - ENCODE_START(7, 6, bl); + ENCODE_START(STRUCT_VERSION, 6, bl); encode(epoch, bl); encode(next_filesystem_id, bl); encode(legacy_client_fscid, bl); - encode(compat, bl); + encode(default_compat, bl); encode(enable_multiple, bl); { std::vector v; @@ -643,13 +641,13 @@ void FSMap::decode(bufferlist::const_iterator& p) { - DECODE_START(7, p); - if (struct_v <= 6) - ceph_abort("detected old mdsmap in mon stores"); + DECODE_START(STRUCT_VERSION, p); + DECODE_OLDEST(7); + struct_version = struct_v; decode(epoch, p); decode(next_filesystem_id, p); decode(legacy_client_fscid, p); - decode(compat, p); + decode(default_compat, p); decode(enable_multiple, p); { std::vector v; @@ -760,8 +758,9 @@ return result; } -const MDSMap::mds_info_t* FSMap::get_available_standby(fs_cluster_id_t fscid) const +const MDSMap::mds_info_t* FSMap::get_available_standby(const Filesystem& fs) const { + const bool upgradeable = fs.is_upgradeable(); const mds_info_t* who = nullptr; for (const auto& [gid, info] : standby_daemons) { ceph_assert(info.rank == MDS_RANK_NONE); @@ -769,9 +768,15 @@ if (info.laggy() || info.is_frozen()) { continue; + } else if (!info.compat.writeable(fs.mds_map.compat)) { + /* standby is not compatible with this fs */ + continue; + } else if (!upgradeable && !fs.mds_map.compat.writeable(info.compat)) { + /* promotion would change fs.mds_map.compat and we're not upgradeable */ + continue; } - if (info.join_fscid == fscid) { + if (info.join_fscid == fs.fscid) { who = &info; break; } else if (info.join_fscid == FS_CLUSTER_ID_NONE) { @@ -826,12 +831,13 @@ /* the standby-replay is frozen, do nothing! */ return nullptr; } else { + ceph_assert(info.compat.writeable(fs->mds_map.compat)); return &info; } } } - return get_available_standby(role.fscid); + return get_available_standby(*fs); } void FSMap::sanity() const @@ -840,21 +846,21 @@ ceph_assert(filesystems.count(legacy_client_fscid) == 1); } - for (const auto &i : filesystems) { - auto fs = i.second; - ceph_assert(fs->mds_map.compat.compare(compat) == 0); - ceph_assert(fs->fscid == i.first); - for (const auto &j : fs->mds_map.mds_info) { - ceph_assert(j.second.rank != MDS_RANK_NONE); - ceph_assert(mds_roles.count(j.first) == 1); - ceph_assert(standby_daemons.count(j.first) == 0); - ceph_assert(standby_epochs.count(j.first) == 0); - ceph_assert(mds_roles.at(j.first) == i.first); - if (j.second.state != MDSMap::STATE_STANDBY_REPLAY) { - ceph_assert(fs->mds_map.up.at(j.second.rank) == j.first); - ceph_assert(fs->mds_map.failed.count(j.second.rank) == 0); - ceph_assert(fs->mds_map.damaged.count(j.second.rank) == 0); + for (const auto& [fscid, fs] : filesystems) { + ceph_assert(fscid == fs->fscid); + for (const auto& [gid, info] : fs->mds_map.mds_info) { + ceph_assert(info.rank != MDS_RANK_NONE); + ceph_assert(mds_roles.at(gid) == fscid); + ceph_assert(standby_daemons.count(gid) == 0); + ceph_assert(standby_epochs.count(gid) == 0); + if (info.state != MDSMap::STATE_STANDBY_REPLAY) { + ceph_assert(fs->mds_map.up.at(info.rank) == gid); + ceph_assert(fs->mds_map.failed.count(info.rank) == 0); + ceph_assert(fs->mds_map.damaged.count(info.rank) == 0); + } else { + ceph_assert(fs->mds_map.allows_standby_replay()); } + ceph_assert(info.compat.writeable(fs->mds_map.compat)); } for (const auto &j : fs->mds_map.up) { @@ -910,7 +916,7 @@ ceph_assert(mds_map.mds_info.at(standby_gid).state == MDSMap::STATE_STANDBY_REPLAY); ceph_assert(mds_map.mds_info.at(standby_gid).rank == assigned_rank); } - auto& info = mds_map.mds_info[standby_gid]; + auto& info = mds_map.mds_info.at(standby_gid); if (mds_map.stopped.erase(assigned_rank)) { // The cluster is being expanded with a stopped rank @@ -925,7 +931,7 @@ } info.rank = assigned_rank; info.inc = epoch; - mds_roles[standby_gid] = filesystem.fscid; + mds_roles.at(standby_gid) = filesystem.fscid; // Update the rank state in Filesystem mds_map.in.insert(assigned_rank); @@ -937,6 +943,11 @@ standby_epochs.erase(standby_gid); } + if (!filesystem.mds_map.compat.writeable(info.compat)) { + ceph_assert(filesystem.is_upgradeable()); + filesystem.mds_map.compat.merge(info.compat); + } + // Indicate that Filesystem has been modified mds_map.epoch = epoch; } diff -Nru ceph-16.2.5/src/mds/FSMap.h ceph-16.2.6/src/mds/FSMap.h --- ceph-16.2.5/src/mds/FSMap.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/FSMap.h 2021-09-16 14:27:19.000000000 +0000 @@ -188,6 +188,10 @@ void dump(ceph::Formatter *f) const; void print(std::ostream& out) const; + bool is_upgradeable() const { + return !mds_map.allows_standby_replay() && mds_map.get_num_in_mds() <= 1; + } + /** * Return true if a daemon is already assigned as * STANDBY_REPLAY for the gid `who` @@ -219,19 +223,23 @@ friend class PaxosFSMap; using mds_info_t = MDSMap::mds_info_t; - FSMap() : compat(MDSMap::get_compat_set_default()) {} + static const version_t STRUCT_VERSION = 7; + static const version_t STRUCT_VERSION_TRIM_TO = 7; + + FSMap() : default_compat(MDSMap::get_compat_set_default()) {} FSMap(const FSMap &rhs) : epoch(rhs.epoch), next_filesystem_id(rhs.next_filesystem_id), legacy_client_fscid(rhs.legacy_client_fscid), - compat(rhs.compat), + default_compat(rhs.default_compat), enable_multiple(rhs.enable_multiple), ever_enabled_multiple(rhs.ever_enabled_multiple), mds_roles(rhs.mds_roles), standby_daemons(rhs.standby_daemons), - standby_epochs(rhs.standby_epochs) + standby_epochs(rhs.standby_epochs), + struct_version(rhs.struct_version) { filesystems.clear(); for (const auto &i : rhs.filesystems) { @@ -242,7 +250,7 @@ FSMap &operator=(const FSMap &rhs); - const CompatSet &get_compat() const {return compat;} + const CompatSet &get_default_compat() const {return default_compat;} void filter(const std::vector& allowed) { @@ -300,7 +308,7 @@ */ std::map get_mds_info() const; - const mds_info_t* get_available_standby(fs_cluster_id_t fscid) const; + const mds_info_t* get_available_standby(const Filesystem& fs) const; /** * Resolve daemon name to GID @@ -400,7 +408,8 @@ */ Filesystem::ref create_filesystem( std::string_view name, int64_t metadata_pool, - int64_t data_pool, uint64_t features); + int64_t data_pool, uint64_t features, + fs_cluster_id_t fscid); /** * Remove the filesystem (it must exist). Caller should already @@ -482,13 +491,6 @@ return filesystems.at(mds_roles.at(who))->get_standby_replay(who); } - /** - * A daemon has told us it's compat, and it's too new - * for the one we had previously. Impose the new one - * on all filesystems. - */ - void update_compat(const CompatSet &c); - Filesystem::const_ref get_legacy_filesystem() { if (legacy_client_fscid == FS_CLUSTER_ID_NONE) { @@ -512,6 +514,11 @@ epoch_t get_epoch() const { return epoch; } void inc_epoch() { epoch++; } + version_t get_struct_version() const { return struct_version; } + bool is_struct_old() const { + return struct_version < STRUCT_VERSION_TRIM_TO; + } + size_t filesystem_count() const {return filesystems.size();} bool filesystem_exists(fs_cluster_id_t fscid) const {return filesystems.count(fscid) > 0;} Filesystem::const_ref get_filesystem(fs_cluster_id_t fscid) const {return std::const_pointer_cast(filesystems.at(fscid));} @@ -577,7 +584,7 @@ epoch_t epoch = 0; uint64_t next_filesystem_id = FS_CLUSTER_ID_ANONYMOUS + 1; fs_cluster_id_t legacy_client_fscid = FS_CLUSTER_ID_NONE; - CompatSet compat; + CompatSet default_compat; bool enable_multiple = true; bool ever_enabled_multiple = true; // < the cluster had multiple FS enabled once @@ -590,6 +597,9 @@ // For MDS daemons not yet assigned to a Filesystem std::map standby_daemons; std::map standby_epochs; + +private: + epoch_t struct_version = 0; }; WRITE_CLASS_ENCODER_FEATURES(FSMap) diff -Nru ceph-16.2.5/src/mds/MDBalancer.cc ceph-16.2.6/src/mds/MDBalancer.cc --- ceph-16.2.5/src/mds/MDBalancer.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/MDBalancer.cc 2021-09-16 14:27:19.000000000 +0000 @@ -300,6 +300,8 @@ } uint64_t num_requests = mds->get_num_requests(); + uint64_t num_traverse = mds->logger->get(l_mds_traverse); + uint64_t num_traverse_hit = mds->logger->get(l_mds_traverse_hit); uint64_t cpu_time = 1; { @@ -331,13 +333,17 @@ load.req_rate = (num_requests - last_num_requests) / el; if (cpu_time > last_cpu_time) load.cpu_load_avg = (cpu_time - last_cpu_time) / el; + if (num_traverse > last_num_traverse && num_traverse_hit > last_num_traverse_hit) + load.cache_hit_rate = (double)(num_traverse_hit - last_num_traverse_hit) / (num_traverse - last_num_traverse); } else { auto p = mds_load.find(mds->get_nodeid()); if (p != mds_load.end()) { load.req_rate = p->second.req_rate; load.cpu_load_avg = p->second.cpu_load_avg; + load.cache_hit_rate = p->second.cache_hit_rate; } - if (num_requests >= last_num_requests && cpu_time >= last_cpu_time) + if (num_requests >= last_num_requests && cpu_time >= last_cpu_time && + num_traverse >= last_num_traverse && num_traverse_hit >= last_num_traverse_hit) update_last = false; } } @@ -346,6 +352,8 @@ last_num_requests = num_requests; last_cpu_time = cpu_time; last_get_load = now; + last_num_traverse = num_traverse; + last_num_traverse_hit = num_traverse_hit; } dout(15) << load << dendl; diff -Nru ceph-16.2.5/src/mds/MDBalancer.h ceph-16.2.6/src/mds/MDBalancer.h --- ceph-16.2.5/src/mds/MDBalancer.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/MDBalancer.h 2021-09-16 14:27:19.000000000 +0000 @@ -137,6 +137,8 @@ time last_get_load = clock::zero(); uint64_t last_num_requests = 0; uint64_t last_cpu_time = 0; + uint64_t last_num_traverse = 0; + uint64_t last_num_traverse_hit = 0; // Dirfrags which are marked to be passed on to MDCache::[split|merge]_dir // just as soon as a delayed context comes back and triggers it. diff -Nru ceph-16.2.5/src/mds/MDCache.cc ceph-16.2.6/src/mds/MDCache.cc --- ceph-16.2.5/src/mds/MDCache.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/MDCache.cc 2021-09-16 14:27:19.000000000 +0000 @@ -5327,7 +5327,7 @@ cap_imports_num_opening--; if (cap_imports_num_opening == 0) { - if (rejoin_gather.empty()) + if (rejoin_gather.empty() && rejoin_ack_gather.count(mds->get_nodeid())) rejoin_gather_finish(); else if (rejoin_gather.count(mds->get_nodeid())) process_imported_caps(); @@ -5349,7 +5349,7 @@ dout(10) << "rejoin_open_sessions_finish" << dendl; mds->server->finish_force_open_sessions(session_map); rejoin_session_map.swap(session_map); - if (rejoin_gather.empty()) + if (rejoin_gather.empty() && rejoin_ack_gather.count(mds->get_nodeid())) rejoin_gather_finish(); } @@ -5973,7 +5973,7 @@ MDSGatherBuilder gather(g_ceph_context, new MDSInternalContextWrapper(mds, new LambdaContext([this](int r) { - if (rejoin_gather.empty()) + if (rejoin_gather.empty() && rejoin_ack_gather.count(mds->get_nodeid())) rejoin_gather_finish(); }) ) diff -Nru ceph-16.2.5/src/mds/MDSMap.cc ceph-16.2.6/src/mds/MDSMap.cc --- ceph-16.2.5/src/mds/MDSMap.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/MDSMap.cc 2021-09-16 14:27:19.000000000 +0000 @@ -104,6 +104,7 @@ f->close_section(); f->dump_unsigned("features", mds_features); f->dump_unsigned("flags", flags); + f->dump_object("compat", compat); } void MDSMap::mds_info_t::dump(std::ostream& o) const @@ -123,7 +124,10 @@ if (join_fscid != FS_CLUSTER_ID_NONE) { o << " join_fscid=" << join_fscid; } - o << " addr " << addrs << "]"; + o << " addr " << addrs; + o << " compat "; + compat.printlite(o); + o << "]"; } void MDSMap::mds_info_t::generate_test_instances(std::list& ls) @@ -522,7 +526,7 @@ void MDSMap::mds_info_t::encode_versioned(bufferlist& bl, uint64_t features) const { - __u8 v = 9; + __u8 v = 10; if (!HAVE_FEATURE(features, SERVER_NAUTILUS)) { v = 7; } @@ -548,6 +552,9 @@ if (v >= 9) { encode(flags, bl); } + if (v >= 10) { + encode(compat, bl); + } ENCODE_FINISH(bl); } @@ -571,7 +578,7 @@ void MDSMap::mds_info_t::decode(bufferlist::const_iterator& bl) { - DECODE_START_LEGACY_COMPAT_LEN(9, 4, 4, bl); + DECODE_START_LEGACY_COMPAT_LEN(10, 4, 4, bl); decode(global_id, bl); decode(name, bl); decode(rank, bl); @@ -604,6 +611,9 @@ if (struct_v >= 9) { decode(flags, bl); } + if (struct_v >= 10) { + decode(compat, bl); + } DECODE_FINISH(bl); } @@ -877,6 +887,15 @@ } } + for (auto& p: mds_info) { + static const CompatSet empty; + auto& info = p.second; + if (empty.compare(info.compat) == 0) { + /* bootstrap old compat; mds_info_t::decode does not have access to MDSMap */ + info.compat = compat; + } + } + DECODE_FINISH(p); } diff -Nru ceph-16.2.5/src/mds/MDSMap.h ceph-16.2.6/src/mds/MDSMap.h --- ceph-16.2.5/src/mds/MDSMap.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/MDSMap.h 2021-09-16 14:27:19.000000000 +0000 @@ -109,6 +109,10 @@ } availability_t; struct mds_info_t { + enum mds_flags : uint64_t { + FROZEN = 1 << 0, + }; + mds_info_t() = default; bool laggy() const { return !(laggy_since == utime_t()); } @@ -151,9 +155,7 @@ fs_cluster_id_t join_fscid = FS_CLUSTER_ID_NONE; uint64_t mds_features = 0; uint64_t flags = 0; - enum mds_flags : uint64_t { - FROZEN = 1 << 0, - }; + CompatSet compat; private: void encode_versioned(ceph::buffer::list& bl, uint64_t features) const; void encode_unversioned(ceph::buffer::list& bl) const; @@ -167,6 +169,13 @@ static CompatSet get_compat_set_default(); static CompatSet get_compat_set_base(); // pre v0.20 + static MDSMap create_null_mdsmap() { + MDSMap null_map; + /* Use the largest epoch so it's always bigger than whatever the MDS has. */ + null_map.epoch = std::numeric_limits::max(); + return null_map; + } + bool get_inline_data_enabled() const { return inline_data_enabled; } void set_inline_data_enabled(bool enabled) { inline_data_enabled = enabled; } diff -Nru ceph-16.2.5/src/mds/MetricsHandler.cc ceph-16.2.6/src/mds/MetricsHandler.cc --- ceph-16.2.5/src/mds/MetricsHandler.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/MetricsHandler.cc 2021-09-16 14:27:19.000000000 +0000 @@ -147,7 +147,7 @@ } void MetricsHandler::handle_payload(Session *session, const CapInfoPayload &payload) { - dout(20) << ": type=" << static_cast(CapInfoPayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", hits=" << payload.cap_hits << ", misses=" << payload.cap_misses << dendl; @@ -163,7 +163,7 @@ } void MetricsHandler::handle_payload(Session *session, const ReadLatencyPayload &payload) { - dout(20) << ": type=" << static_cast(ReadLatencyPayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", latency=" << payload.lat << dendl; auto it = client_metrics_map.find(session->info.inst); @@ -178,7 +178,7 @@ } void MetricsHandler::handle_payload(Session *session, const WriteLatencyPayload &payload) { - dout(20) << ": type=" << static_cast(WriteLatencyPayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", latency=" << payload.lat << dendl; auto it = client_metrics_map.find(session->info.inst); @@ -193,8 +193,8 @@ } void MetricsHandler::handle_payload(Session *session, const MetadataLatencyPayload &payload) { - dout(20) << ": type=" << static_cast(MetadataLatencyPayload::METRIC_TYPE) - << ", session=" << session << ", latenc]y=" << payload.lat << dendl; + dout(20) << ": type=" << payload.get_type() + << ", session=" << session << ", latency=" << payload.lat << dendl; auto it = client_metrics_map.find(session->info.inst); if (it == client_metrics_map.end()) { @@ -208,7 +208,7 @@ } void MetricsHandler::handle_payload(Session *session, const DentryLeasePayload &payload) { - dout(20) << ": type=" << static_cast(DentryLeasePayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", hits=" << payload.dlease_hits << ", misses=" << payload.dlease_misses << dendl; @@ -225,7 +225,7 @@ } void MetricsHandler::handle_payload(Session *session, const OpenedFilesPayload &payload) { - dout(20) << ": type=" << static_cast(OpenedFilesPayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", opened_files=" << payload.opened_files << ", total_inodes=" << payload.total_inodes << dendl; @@ -242,7 +242,7 @@ } void MetricsHandler::handle_payload(Session *session, const PinnedIcapsPayload &payload) { - dout(20) << ": type=" << static_cast(PinnedIcapsPayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", pinned_icaps=" << payload.pinned_icaps << ", total_inodes=" << payload.total_inodes << dendl; @@ -259,7 +259,7 @@ } void MetricsHandler::handle_payload(Session *session, const OpenedInodesPayload &payload) { - dout(20) << ": type=" << static_cast(OpenedInodesPayload::METRIC_TYPE) + dout(20) << ": type=" << payload.get_type() << ", session=" << session << ", opened_inodes=" << payload.opened_inodes << ", total_inodes=" << payload.total_inodes << dendl; diff -Nru ceph-16.2.5/src/mds/Server.cc ceph-16.2.6/src/mds/Server.cc --- ceph-16.2.5/src/mds/Server.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mds/Server.cc 2021-09-16 14:27:19.000000000 +0000 @@ -4757,7 +4757,7 @@ mdr->reply_extra_bl = dirbl; // bump popularity. NOTE: this doesn't quite capture it. - mds->balancer->hit_dir(dir, META_POP_IRD, -1, numfiles); + mds->balancer->hit_dir(dir, META_POP_READDIR, -1, numfiles); // reply mdr->tracei = diri; @@ -10250,6 +10250,7 @@ } if (!mds->mdsmap->allows_snaps()) { // you can't make snapshots until you set an option right now + dout(5) << "new snapshots are disabled for this fs" << dendl; respond_to_request(mdr, -CEPHFS_EPERM); return; } @@ -10265,6 +10266,7 @@ } if (diri->is_system() && !diri->is_root()) { // no snaps in system dirs (root is ok) + dout(5) << "is an internal system dir" << dendl; respond_to_request(mdr, -CEPHFS_EPERM); return; } @@ -10298,6 +10300,7 @@ if (inodeno_t subvol_ino = diri->find_snaprealm()->get_subvolume_ino(); (subvol_ino && subvol_ino != diri->ino())) { + dout(5) << "is a descendent of a subvolume dir" << dendl; respond_to_request(mdr, -CEPHFS_EPERM); return; } diff -Nru ceph-16.2.5/src/mgr/DaemonServer.cc ceph-16.2.6/src/mgr/DaemonServer.cc --- ceph-16.2.5/src/mgr/DaemonServer.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mgr/DaemonServer.cc 2021-09-16 14:27:19.000000000 +0000 @@ -2867,11 +2867,13 @@ } } } - dout(10) << "pool " << i.first - << " pgp_num_target " << p.get_pgp_num_target() - << " pgp_num " << p.get_pgp_num() - << " -> " << next << dendl; - pgp_num_to_set[osdmap.get_pool_name(i.first)] = next; + if (next != p.get_pgp_num()) { + dout(10) << "pool " << i.first + << " pgp_num_target " << p.get_pgp_num_target() + << " pgp_num " << p.get_pgp_num() + << " -> " << next << dendl; + pgp_num_to_set[osdmap.get_pool_name(i.first)] = next; + } } } if (left == 0) { diff -Nru ceph-16.2.5/src/mon/CMakeLists.txt ceph-16.2.6/src/mon/CMakeLists.txt --- ceph-16.2.5/src/mon/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -33,7 +33,10 @@ add_library(mon STATIC ${lib_mon_srcs}) -target_link_libraries(mon kv heap_profiler) +target_link_libraries(mon + kv + heap_profiler + fmt::fmt) if(WITH_JAEGER) target_link_libraries(mon jaeger-base) endif() diff -Nru ceph-16.2.5/src/mon/FSCommands.cc ceph-16.2.6/src/mon/FSCommands.cc --- ceph-16.2.5/src/mon/FSCommands.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/FSCommands.cc 2021-09-16 14:27:19.000000000 +0000 @@ -27,12 +27,9 @@ using std::list; using std::map; using std::make_pair; -using std::ostream; -using std::ostringstream; using std::pair; using std::set; using std::string; -using std::stringstream; using std::to_string; using std::vector; @@ -60,7 +57,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { string flag_name; cmd_getval(cmdmap, "flag_name", flag_name); @@ -101,7 +98,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream& ss) override + std::ostream& ss) override { if (!mon->osdmon()->is_writeable()) { // not allowed to write yet, so retry when we can @@ -158,7 +155,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { ceph_assert(m_paxos->is_plugged()); @@ -241,6 +238,18 @@ } } + int64_t fscid = FS_CLUSTER_ID_NONE; + if (cmd_getval(cmdmap, "fscid", fscid)) { + if (!force) { + ss << "Pass --force to create a file system with a specific ID"; + return -EINVAL; + } + if (fsmap.filesystem_exists(fscid)) { + ss << "filesystem already exists with id '" << fscid << "'"; + return -EINVAL; + } + } + pg_pool_t const *data_pool = mon->osdmon()->osdmap.get_pg_pool(data); ceph_assert(data_pool != NULL); // Checked it existed above pg_pool_t const *metadata_pool = mon->osdmon()->osdmap.get_pg_pool(metadata); @@ -280,7 +289,7 @@ // All checks passed, go ahead and create. auto&& fs = fsmap.create_filesystem(fs_name, metadata, data, - mon->get_quorum_con_features()); + mon->get_quorum_con_features(), fscid); ss << "new fs with metadata pool " << metadata << " and data pool " << data; @@ -312,7 +321,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { std::string fs_name; if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { @@ -388,11 +397,6 @@ { fs->mds_map.set_inline_data_enabled(true); }); - - // Update `compat` - CompatSet c = fsmap.get_compat(); - c.incompat.insert(MDS_FEATURE_INCOMPAT_INLINE); - fsmap.update_compat(c); } else { ss << "inline data disabled"; fsmap.modify_filesystem( @@ -659,6 +663,111 @@ } }; +class CompatSetHandler : public FileSystemCommandHandler +{ + public: + CompatSetHandler() + : FileSystemCommandHandler("fs compat") + { + } + + int handle( + Monitor *mon, + FSMap &fsmap, + MonOpRequestRef op, + const cmdmap_t& cmdmap, + std::ostream &ss) override + { + static const std::set subops = {"rm_incompat", "rm_compat", "add_incompat", "add_compat"}; + + std::string fs_name; + if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { + ss << "Missing filesystem name"; + return -EINVAL; + } + auto fs = fsmap.get_filesystem(fs_name); + if (fs == nullptr) { + ss << "Not found: '" << fs_name << "'"; + return -ENOENT; + } + + string subop; + if (!cmd_getval(cmdmap, "subop", subop) || subops.count(subop) == 0) { + ss << "subop `" << subop << "' not recognized. Must be one of: " << subops; + return -EINVAL; + } + + int64_t feature; + if (!cmd_getval(cmdmap, "feature", feature) || feature <= 0) { + ss << "Invalid feature"; + return -EINVAL; + } + + if (fs->mds_map.get_num_up_mds() > 0) { + ss << "file system must be failed or down; use `ceph fs fail` to bring down"; + return -EBUSY; + } + + CompatSet cs = fs->mds_map.compat; + if (subop == "rm_compat") { + if (cs.compat.contains(feature)) { + ss << "removed compat feature " << feature; + cs.compat.remove(feature); + } else { + ss << "already removed compat feature " << feature; + } + } else if (subop == "rm_incompat") { + if (cs.incompat.contains(feature)) { + ss << "removed incompat feature " << feature; + cs.incompat.remove(feature); + } else { + ss << "already removed incompat feature " << feature; + } + } else if (subop == "add_compat" || subop == "add_incompat") { + string feature_str; + if (!cmd_getval(cmdmap, "feature_str", feature_str) || feature_str.empty()) { + ss << "adding a feature requires a feature string"; + return -EINVAL; + } + auto f = CompatSet::Feature(feature, feature_str); + if (subop == "add_compat") { + if (cs.compat.contains(feature)) { + auto name = cs.compat.get_name(feature); + if (name == feature_str) { + ss << "feature already exists"; + } else { + ss << "feature with differing name `" << name << "' exists"; + return -EEXIST; + } + } else { + cs.compat.insert(f); + ss << "added compat feature " << f; + } + } else if (subop == "add_incompat") { + if (cs.incompat.contains(feature)) { + auto name = cs.incompat.get_name(feature); + if (name == feature_str) { + ss << "feature already exists"; + } else { + ss << "feature with differing name `" << name << "' exists"; + return -EEXIST; + } + } else { + cs.incompat.insert(f); + ss << "added incompat feature " << f; + } + } else ceph_assert(0); + } else ceph_assert(0); + + auto modifyf = [cs = std::move(cs)](auto&& fs) { + fs->mds_map.compat = cs; + }; + + fsmap.modify_filesystem(fs->fscid, std::move(modifyf)); + return 0; + } +}; + class RequiredClientFeaturesHandler : public FileSystemCommandHandler { public: @@ -672,7 +781,7 @@ FSMap &fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { std::string fs_name; if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { @@ -764,7 +873,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { ceph_assert(m_paxos->is_plugged()); @@ -838,7 +947,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { std::string fs_name; cmd_getval(cmdmap, "fs_name", fs_name); @@ -865,7 +974,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { /* We may need to blocklist ranks. */ if (!mon->osdmon()->is_writeable()) { @@ -939,7 +1048,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { string fs_name; cmd_getval(cmdmap, "fs_name", fs_name); @@ -984,7 +1093,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { string poolname; cmd_getval(cmdmap, "pool", poolname); @@ -1059,7 +1168,7 @@ FSMap& fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) override + std::ostream &ss) override { return T::handle(mon, fsmap, op, cmdmap, ss); } @@ -1074,7 +1183,7 @@ int handle(Monitor *mon, FSMap &fsmap, MonOpRequestRef op, - const cmdmap_t& cmdmap, std::stringstream &ss) override { + const cmdmap_t& cmdmap, std::ostream &ss) override { std::string fs_name; if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { ss << "Missing filesystem name"; @@ -1109,7 +1218,7 @@ int handle(Monitor *mon, FSMap &fsmap, MonOpRequestRef op, - const cmdmap_t& cmdmap, std::stringstream &ss) override { + const cmdmap_t& cmdmap, std::ostream &ss) override { std::string fs_name; if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { ss << "Missing filesystem name"; @@ -1156,7 +1265,7 @@ } bool peer_add(FSMap &fsmap, Filesystem::const_ref &&fs, - const cmdmap_t &cmdmap, std::stringstream &ss) { + const cmdmap_t &cmdmap, std::ostream &ss) { string peer_uuid; string remote_spec; string remote_fs_name; @@ -1191,7 +1300,7 @@ int handle(Monitor *mon, FSMap &fsmap, MonOpRequestRef op, - const cmdmap_t& cmdmap, std::stringstream &ss) override { + const cmdmap_t& cmdmap, std::ostream &ss) override { std::string fs_name; if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { ss << "Missing filesystem name"; @@ -1226,7 +1335,7 @@ {} bool peer_remove(FSMap &fsmap, Filesystem::const_ref &&fs, - const cmdmap_t &cmdmap, std::stringstream &ss) { + const cmdmap_t &cmdmap, std::ostream &ss) { string peer_uuid; cmd_getval(cmdmap, "uuid", peer_uuid); @@ -1244,7 +1353,7 @@ int handle(Monitor *mon, FSMap &fsmap, MonOpRequestRef op, - const cmdmap_t& cmdmap, std::stringstream &ss) override { + const cmdmap_t& cmdmap, std::ostream &ss) override { std::string fs_name; if (!cmd_getval(cmdmap, "fs_name", fs_name) || fs_name.empty()) { ss << "Missing filesystem name"; @@ -1279,6 +1388,7 @@ handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared()); + handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared()); handlers.push_back(std::make_shared(paxos)); handlers.push_back(std::make_shared()); @@ -1302,7 +1412,7 @@ const int64_t pool_id, int type, bool force, - std::stringstream *ss) const + std::ostream *ss) const { ceph_assert(ss != NULL); @@ -1372,7 +1482,7 @@ int FileSystemCommandHandler::is_op_allowed( const MonOpRequestRef& op, const FSMap& fsmap, const cmdmap_t& cmdmap, - std::stringstream &ss) const + std::ostream &ss) const { string fs_name; cmd_getval(cmdmap, "fs_name", fs_name); diff -Nru ceph-16.2.5/src/mon/FSCommands.h ceph-16.2.6/src/mon/FSCommands.h --- ceph-16.2.5/src/mon/FSCommands.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/FSCommands.h 2021-09-16 14:27:19.000000000 +0000 @@ -23,7 +23,7 @@ #include "mds/FSMap.h" #include -#include +#include class FileSystemCommandHandler : protected CommandHandler { @@ -38,7 +38,7 @@ /** * Return 0 if the pool is suitable for use with CephFS, or * in case of errors return a negative error code, and populate - * the passed stringstream with an explanation. + * the passed ostream with an explanation. * * @param metadata whether the pool will be for metadata (stricter checks) */ @@ -47,7 +47,7 @@ const int64_t pool_id, int type, bool force, - std::stringstream *ss) const; + std::ostream *ss) const; virtual std::string const &get_prefix() const {return prefix;} @@ -60,10 +60,10 @@ {} int is_op_allowed(const MonOpRequestRef& op, const FSMap& fsmap, - const cmdmap_t& cmdmap, std::stringstream &ss) const; + const cmdmap_t& cmdmap, std::ostream &ss) const; int can_handle(std::string const &prefix_, MonOpRequestRef& op, FSMap& fsmap, - const cmdmap_t& cmdmap, std::stringstream &ss) const + const cmdmap_t& cmdmap, std::ostream &ss) const { if (get_prefix() != prefix_) { return 0; @@ -87,7 +87,7 @@ FSMap &fsmap, MonOpRequestRef op, const cmdmap_t& cmdmap, - std::stringstream &ss) = 0; + std::ostream &ss) = 0; }; #endif diff -Nru ceph-16.2.5/src/mon/KVMonitor.cc ceph-16.2.6/src/mon/KVMonitor.cc --- ceph-16.2.5/src/mon/KVMonitor.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/KVMonitor.cc 2021-09-16 14:27:19.000000000 +0000 @@ -47,6 +47,9 @@ dout(10) << __func__ << dendl; version = 0; pending.clear(); + bufferlist bl; + bl.append("scale-down"); + pending["config/mgr/mgr/pg_autoscaler/autoscale_profile"] = bl; } void KVMonitor::update_from_paxos(bool *need_bootstrap) diff -Nru ceph-16.2.5/src/mon/MDSMonitor.cc ceph-16.2.6/src/mon/MDSMonitor.cc --- ceph-16.2.5/src/mon/MDSMonitor.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/MDSMonitor.cc 2021-09-16 14:27:19.000000000 +0000 @@ -146,7 +146,12 @@ ceph_assert(fsmap_bl.length() > 0); dout(10) << __func__ << " got " << version << dendl; - PaxosFSMap::decode(fsmap_bl); + try { + PaxosFSMap::decode(fsmap_bl); + } catch (const ceph::buffer::malformed_input& e) { + derr << "unable to decode FSMap: " << e.what() << dendl; + throw; + } // new map dout(0) << "new map" << dendl; @@ -290,7 +295,7 @@ { version_t floor = 0; if (g_conf()->mon_mds_force_trim_to > 0 && - g_conf()->mon_mds_force_trim_to < (int)get_last_committed()) { + g_conf()->mon_mds_force_trim_to <= (int)get_last_committed()) { floor = g_conf()->mon_mds_force_trim_to; dout(10) << __func__ << " explicit mon_mds_force_trim_to = " << floor << dendl; @@ -299,8 +304,11 @@ unsigned max = g_conf()->mon_max_mdsmap_epochs; version_t last = get_last_committed(); - if (last - get_first_committed() > max && floor < last - max) - return last - max; + if (last - get_first_committed() > max && floor < last - max) { + floor = last-max; + } + + dout(20) << __func__ << " = " << floor << dendl; return floor; } @@ -384,14 +392,6 @@ goto ignore; } - // check compat - if (!m->get_compat().writeable(fsmap.compat)) { - dout(1) << " mds " << m->get_orig_source() - << " " << m->get_orig_source_addrs() - << " can't write to fsmap " << fsmap.compat << dendl; - goto ignore; - } - // fw to leader? if (!is_leader()) return false; @@ -406,10 +406,7 @@ * know which FS it was part of. Nor does this matter. Sending an empty * MDSMap is sufficient for getting the MDS to respawn. */ - MDSMap null_map; - null_map.epoch = fsmap.epoch; - null_map.compat = fsmap.compat; - auto m = make_message(mon.monmap->fsid, null_map); + auto m = make_message(mon.monmap->fsid, MDSMap::create_null_mdsmap()); mon.send_reply(op, m.detach()); return true; } else { @@ -634,7 +631,7 @@ // Store health pending_daemon_health[gid] = m->get_health(); - // boot? + const auto& cs = m->get_compat(); if (state == MDSMap::STATE_BOOT) { // zap previous instance of this name? if (g_conf()->mds_enforce_unique_name) { @@ -644,8 +641,7 @@ mon.osdmon()->wait_for_writeable(op, new C_RetryMessage(this, op)); return false; } - const MDSMap::mds_info_t &existing_info = - pending.get_info_gid(existing); + const auto& existing_info = pending.get_info_gid(existing); mon.clog->info() << existing_info.human_name() << " restarted"; fail_mds_gid(pending, existing); failed_mds = true; @@ -665,7 +661,7 @@ new_info.mds_features = m->get_mds_features(); new_info.state = MDSMap::STATE_STANDBY; new_info.state_seq = seq; - pending.insert(new_info); + new_info.compat = cs; if (m->get_fs().size()) { fs_cluster_id_t fscid = FS_CLUSTER_ID_NONE; auto f = pending.get_filesystem(m->get_fs()); @@ -674,6 +670,7 @@ } new_info.join_fscid = fscid; } + pending.insert(new_info); } // initialize the beacon timer @@ -681,15 +678,6 @@ beacon.stamp = mono_clock::now(); beacon.seq = seq; - // new incompat? - if (!pending.compat.writeable(m->get_compat())) { - dout(10) << " fsmap " << pending.compat - << " can't write to new mds' " << m->get_compat() - << ", updating fsmap and killing old mds's" - << dendl; - pending.update_compat(m->get_compat()); - } - update_metadata(m->get_global_id(), m->get_sys_info()); } else { // state update @@ -705,11 +693,7 @@ */ wait_for_finished_proposal(op, new LambdaContext([op, this](int r){ if (r >= 0) { - const auto& fsmap = get_fsmap(); - MDSMap null_map; - null_map.epoch = fsmap.epoch; - null_map.compat = fsmap.compat; - auto m = make_message(mon.monmap->fsid, null_map); + auto m = make_message(mon.monmap->fsid, MDSMap::create_null_mdsmap()); mon.send_reply(op, m.detach()); } else { dispatch(op); // try again @@ -719,6 +703,19 @@ } const auto& info = pending.get_info_gid(gid); + + // did the reported compat change? That's illegal! + if (cs.compare(info.compat) != 0) { + if (!mon.osdmon()->is_writeable()) { + mon.osdmon()->wait_for_writeable(op, new C_RetryMessage(this, op)); + return false; + } + mon.clog->warn() << info.human_name() << " compat changed unexpectedly"; + fail_mds_gid(pending, gid); + request_proposal(mon.osdmon()); + return true; + } + if (info.state == MDSMap::STATE_STOPPING && state != MDSMap::STATE_STOPPING && state != MDSMap::STATE_STOPPED) { @@ -901,10 +898,7 @@ if (m->get_state() == MDSMap::STATE_STOPPED) { // send the map manually (they're out of the map, so they won't get it automatic) - MDSMap null_map; - null_map.epoch = fsmap.epoch; - null_map.compat = fsmap.compat; - auto m = make_message(mon.monmap->fsid, null_map); + auto m = make_message(mon.monmap->fsid, MDSMap::create_null_mdsmap()); mon.send_reply(op, m.detach()); } else { auto beacon = make_message(mon.monmap->fsid, @@ -1117,14 +1111,33 @@ count_metadata(field, f.get()); f->flush(ds); r = 0; + } else if (prefix == "fs compat show") { + string fs_name; + cmd_getval(cmdmap, "fs_name", fs_name); + const auto &fs = fsmap.get_filesystem(fs_name); + if (fs == nullptr) { + ss << "filesystem '" << fs_name << "' not found"; + r = -ENOENT; + goto out; + } + + if (f) { + f->open_object_section("mds_compat"); + fs->mds_map.compat.dump(f.get()); + f->close_section(); + f->flush(ds); + } else { + ds << fs->mds_map.compat; + } + r = 0; } else if (prefix == "mds compat show") { if (f) { f->open_object_section("mds_compat"); - fsmap.compat.dump(f.get()); + fsmap.default_compat.dump(f.get()); f->close_section(); f->flush(ds); } else { - ds << fsmap.compat; + ds << fsmap.default_compat; } r = 0; } else if (prefix == "fs get") { @@ -1546,6 +1559,7 @@ ss << "removed failed mds." << role; return 0; + /* TODO: convert to fs commands to update defaults */ } else if (prefix == "mds compat rm_compat") { int64_t f; if (!cmd_getval(cmdmap, "feature", f)) { @@ -1553,13 +1567,11 @@ << cmd_vartype_stringify(cmdmap.at("feature")) << "'"; return -EINVAL; } - if (fsmap.compat.compat.contains(f)) { + if (fsmap.default_compat.compat.contains(f)) { ss << "removing compat feature " << f; - CompatSet modified = fsmap.compat; - modified.compat.remove(f); - fsmap.update_compat(modified); + fsmap.default_compat.compat.remove(f); } else { - ss << "compat feature " << f << " not present in " << fsmap.compat; + ss << "compat feature " << f << " not present in " << fsmap.default_compat; } r = 0; } else if (prefix == "mds compat rm_incompat") { @@ -1569,13 +1581,11 @@ << cmd_vartype_stringify(cmdmap.at("feature")) << "'"; return -EINVAL; } - if (fsmap.compat.incompat.contains(f)) { + if (fsmap.default_compat.incompat.contains(f)) { ss << "removing incompat feature " << f; - CompatSet modified = fsmap.compat; - modified.incompat.remove(f); - fsmap.update_compat(modified); + fsmap.default_compat.incompat.remove(f); } else { - ss << "incompat feature " << f << " not present in " << fsmap.compat; + ss << "incompat feature " << f << " not present in " << fsmap.default_compat; } r = 0; } else if (prefix == "mds repaired") { @@ -1763,8 +1773,7 @@ // Work out the effective latest epoch const MDSMap *mds_map = nullptr; - MDSMap null_map; - null_map.compat = fsmap.compat; + MDSMap null_map = MDSMap::create_null_mdsmap(); if (fscid == FS_CLUSTER_ID_NONE) { // For a client, we should have already dropped out ceph_assert(is_mds); @@ -2176,7 +2185,7 @@ const auto state = info.state; const mds_info_t* rep_info = nullptr; if (state == MDSMap::STATE_STANDBY_REPLAY) { - rep_info = fsmap.get_available_standby(fscid); + rep_info = fsmap.get_available_standby(*fs); } else if (state == MDSMap::STATE_ACTIVE) { rep_info = fsmap.find_replacement_for({fscid, rank}); } else { @@ -2245,7 +2254,7 @@ // as standby-replay daemons. Don't do this when the cluster is degraded // as a standby-replay daemon may try to read a journal being migrated. for (;;) { - auto info = fsmap.get_available_standby(fs.fscid); + auto info = fsmap.get_available_standby(fs); if (!info) break; dout(20) << "standby available mds." << info->global_id << dendl; bool changed = false; @@ -2276,6 +2285,34 @@ bool do_propose = false; bool propose_osdmap = false; + if (check_fsmap_struct_version) { + /* Allow time for trimming otherwise PaxosService::is_writeable will always + * be false. + */ + + auto now = clock::now(); + auto elapsed = now - last_fsmap_struct_flush; + if (elapsed > std::chrono::seconds(30)) { + FSMap fsmap; + bufferlist bl; + auto v = get_first_committed(); + int err = get_version(v, bl); + if (err) { + derr << "could not get version " << v << dendl; + ceph_abort(); + } + fsmap.decode(bl); + if (fsmap.is_struct_old()) { + dout(5) << "fsmap struct is too old; proposing to flush out old versions" << dendl; + do_propose = true; + last_fsmap_struct_flush = now; + } else { + dout(20) << "struct is recent" << dendl; + check_fsmap_struct_version = false; + } + } + } + do_propose |= pending.check_health(); /* Check health and affinity of ranks */ diff -Nru ceph-16.2.5/src/mon/MDSMonitor.h ceph-16.2.6/src/mon/MDSMonitor.h --- ceph-16.2.5/src/mon/MDSMonitor.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/MDSMonitor.h 2021-09-16 14:27:19.000000000 +0000 @@ -32,6 +32,9 @@ class MDSMonitor : public PaxosService, public PaxosFSMap, protected CommandHandler { public: + using clock = ceph::coarse_mono_clock; + using time = ceph::coarse_mono_time; + MDSMonitor(Monitor &mn, Paxos &p, std::string service_name); // service methods @@ -146,6 +149,10 @@ // when the mon was not updating us for some period (e.g. during slow // election) to reset last_beacon timeouts ceph::mono_time last_tick = ceph::mono_clock::zero(); + +private: + time last_fsmap_struct_flush = clock::zero(); + bool check_fsmap_struct_version = true; }; #endif diff -Nru ceph-16.2.5/src/mon/MonCommands.h ceph-16.2.6/src/mon/MonCommands.h --- ceph-16.2.5/src/mon/MonCommands.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/MonCommands.h 2021-09-16 14:27:19.000000000 +0000 @@ -299,8 +299,6 @@ "name=who,type=CephString " "name=args,type=CephString,n=N", "send command to particular mds", "mds", "rw", FLAG(OBSOLETE)) -COMMAND("mds compat show", "show mds compatibility settings", - "mds", "r") COMMAND_WITH_FLAG("mds stop name=role,type=CephString", "stop mds", "mds", "rw", FLAG(OBSOLETE)) COMMAND_WITH_FLAG("mds deactivate name=role,type=CephString", @@ -341,12 +339,18 @@ "remove failed rank", "mds", "rw", FLAG(HIDDEN)) COMMAND_WITH_FLAG("mds cluster_down", "take MDS cluster down", "mds", "rw", FLAG(OBSOLETE)) COMMAND_WITH_FLAG("mds cluster_up", "bring MDS cluster up", "mds", "rw", FLAG(OBSOLETE)) -COMMAND("mds compat rm_compat " +COMMAND_WITH_FLAG("mds compat show", "show mds compatibility settings", + "mds", "r", FLAG(DEPRECATED)) +COMMAND("fs compat show " + "name=fs_name,type=CephString ", + "show fs compatibility settings", + "mds", "r") +COMMAND_WITH_FLAG("mds compat rm_compat " "name=feature,type=CephInt,range=0", - "remove compatible feature", "mds", "rw") -COMMAND("mds compat rm_incompat " + "remove compatible feature", "mds", "rw", FLAG(DEPRECATED)) +COMMAND_WITH_FLAG("mds compat rm_incompat " "name=feature,type=CephInt,range=0", - "remove incompatible feature", "mds", "rw") + "remove incompatible feature", "mds", "rw", FLAG(DEPRECATED)) COMMAND_WITH_FLAG("mds add_data_pool " "name=pool,type=CephString", "add data pool ", "mds", "rw", FLAG(OBSOLETE)) @@ -367,7 +371,8 @@ "name=metadata,type=CephString " "name=data,type=CephString " "name=force,type=CephBool,req=false " - "name=allow_dangerous_metadata_overlay,type=CephBool,req=false", + "name=allow_dangerous_metadata_overlay,type=CephBool,req=false " + "name=fscid,type=CephInt,range=0,req=false", "make new filesystem using named pools and ", "fs", "rw") COMMAND("fs fail " @@ -410,6 +415,13 @@ "list available cephfs features to be set/unset", "mds", "r") +COMMAND("fs compat " + "name=fs_name,type=CephString " + "name=subop,type=CephChoices,strings=rm_compat|rm_incompat|add_compat|add_incompat " + "name=feature,type=CephInt " + "name=feature_str,type=CephString,req=false ", + "manipulate compat settings", "fs", "rw") + COMMAND("fs required_client_features " "name=fs_name,type=CephString " "name=subop,type=CephChoices,strings=add|rm " diff -Nru ceph-16.2.5/src/mon/Monitor.cc ceph-16.2.6/src/mon/Monitor.cc --- ceph-16.2.5/src/mon/Monitor.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/Monitor.cc 2021-09-16 14:27:19.000000000 +0000 @@ -3690,7 +3690,7 @@ rs = ss2.str(); r = 0; } else if (prefix == "osd last-stat-seq") { - int64_t osd; + int64_t osd = 0; cmd_getval(cmdmap, "id", osd); uint64_t seq = mgrstatmon()->get_last_osd_stat_seq(osd); if (f) { diff -Nru ceph-16.2.5/src/mon/OSDMonitor.cc ceph-16.2.6/src/mon/OSDMonitor.cc --- ceph-16.2.5/src/mon/OSDMonitor.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/OSDMonitor.cc 2021-09-16 14:27:19.000000000 +0000 @@ -341,11 +341,14 @@ } // anonymous namespace -void LastEpochClean::Lec::report(ps_t ps, epoch_t last_epoch_clean) +void LastEpochClean::Lec::report(unsigned pg_num, ps_t ps, + epoch_t last_epoch_clean) { - if (epoch_by_pg.size() <= ps) { - epoch_by_pg.resize(ps + 1, 0); + if (ps >= pg_num) { + // removed PG + return; } + epoch_by_pg.resize(pg_num, 0); const auto old_lec = epoch_by_pg[ps]; if (old_lec >= last_epoch_clean) { // stale lec @@ -377,10 +380,11 @@ report_by_pool.erase(pool); } -void LastEpochClean::report(const pg_t& pg, epoch_t last_epoch_clean) +void LastEpochClean::report(unsigned pg_num, const pg_t& pg, + epoch_t last_epoch_clean) { auto& lec = report_by_pool[pg.pool()]; - return lec.report(pg.ps(), last_epoch_clean); + return lec.report(pg_num, pg.ps(), last_epoch_clean); } epoch_t LastEpochClean::get_lower_bound(const OSDMap& latest) const @@ -4419,7 +4423,10 @@ osd_epochs[from] = beacon->version; for (const auto& pg : beacon->pgs) { - last_epoch_clean.report(pg, beacon->min_last_epoch_clean); + if (auto* pool = osdmap.get_pg_pool(pg.pool()); pool != nullptr) { + unsigned pg_num = pool->get_pg_num(); + last_epoch_clean.report(pg_num, pg, beacon->min_last_epoch_clean); + } } if (osdmap.osd_xinfo[from].last_purged_snaps_scrub < @@ -6191,6 +6198,13 @@ } } else /* var != "all" */ { choices_map_t::const_iterator found = ALL_CHOICES.find(var); + if (found == ALL_CHOICES.end()) { + ss << "pool '" << poolstr + << "': invalid variable: '" << var << "'"; + r = -EINVAL; + goto reply; + } + osd_pool_get_choices selected = found->second; if (!p->is_tier() && @@ -7716,6 +7730,43 @@ return err; } +int OSDMonitor::get_replicated_stretch_crush_rule() +{ + /* we don't write down the stretch rule anywhere, so + * we have to guess it. How? Look at all the pools + * and count up how many times a given rule is used + * on stretch pools and then return the one with + * the most users! + */ + map rule_counts; + for (const auto& pooli : osdmap.pools) { + const pg_pool_t& p = pooli.second; + if (p.is_replicated() && p.is_stretch_pool()) { + if (!rule_counts.count(p.crush_rule)) { + rule_counts[p.crush_rule] = 1; + } else { + ++rule_counts[p.crush_rule]; + } + } + } + + if (rule_counts.empty()) { + return -ENOENT; + } + + int most_used_count = 0; + int most_used_rule = -1; + for (auto i : rule_counts) { + if (i.second > most_used_count) { + most_used_rule = i.first; + most_used_count = i.second; + } + } + ceph_assert(most_used_count > 0); + ceph_assert(most_used_rule >= 0); + return most_used_rule; +} + int OSDMonitor::prepare_pool_crush_rule(const unsigned pool_type, const string &erasure_code_profile, const string &rule_name, @@ -7728,8 +7779,12 @@ case pg_pool_t::TYPE_REPLICATED: { if (rule_name == "") { - // Use default rule - *crush_rule = osdmap.crush->get_osd_pool_default_crush_replicated_ruleset(cct); + if (osdmap.stretch_mode_enabled) { + *crush_rule = get_replicated_stretch_crush_rule(); + } else { + // Use default rule + *crush_rule = osdmap.crush->get_osd_pool_default_crush_replicated_ruleset(cct); + } if (*crush_rule < 0) { // Errors may happen e.g. if no valid rule is available *ss << "No suitable CRUSH rule exists, check " diff -Nru ceph-16.2.5/src/mon/OSDMonitor.h ceph-16.2.6/src/mon/OSDMonitor.h --- ceph-16.2.5/src/mon/OSDMonitor.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/OSDMonitor.h 2021-09-16 14:27:19.000000000 +0000 @@ -107,11 +107,11 @@ std::vector epoch_by_pg; ps_t next_missing = 0; epoch_t floor = std::numeric_limits::max(); - void report(ps_t pg, epoch_t last_epoch_clean); + void report(unsigned pg_num, ps_t pg, epoch_t last_epoch_clean); }; std::map report_by_pool; public: - void report(const pg_t& pg, epoch_t last_epoch_clean); + void report(unsigned pg_num, const pg_t& pg, epoch_t last_epoch_clean); void remove_pool(uint64_t pool); epoch_t get_lower_bound(const OSDMap& latest) const; @@ -858,6 +858,13 @@ * Sets the osdmap and pg_pool_t values back to healthy stretch mode status. */ void trigger_healthy_stretch_mode(); + /** + * Obtain the crush rule being used for stretch pools. + * Note that right now this is heuristic and simply selects the + * most-used rule on replicated stretch pools. + * @return the crush rule ID, or a negative errno + */ + int get_replicated_stretch_crush_rule(); private: utime_t stretch_recovery_triggered; // what time we committed a switch to recovery mode }; diff -Nru ceph-16.2.5/src/mon/PaxosService.cc ceph-16.2.6/src/mon/PaxosService.cc --- ceph-16.2.5/src/mon/PaxosService.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/PaxosService.cc 2021-09-16 14:27:19.000000000 +0000 @@ -377,14 +377,17 @@ if (!is_writeable()) return; + const version_t first_committed = get_first_committed(); version_t trim_to = get_trim_to(); - if (trim_to < get_first_committed()) { - dout(10) << __func__ << " trim_to " << trim_to << " < first_committed" - << get_first_committed() << dendl; + dout(20) << __func__ << " " << first_committed << "~" << trim_to << dendl; + + if (trim_to < first_committed) { + dout(10) << __func__ << " trim_to " << trim_to << " < first_committed " + << first_committed << dendl; return; } - version_t to_remove = trim_to - get_first_committed(); + version_t to_remove = trim_to - first_committed; const version_t trim_min = g_conf().get_val("paxos_service_trim_min"); if (trim_min > 0 && to_remove < trim_min) { @@ -393,13 +396,13 @@ return; } - to_remove = [to_remove, this] { + to_remove = [to_remove, trim_to, this] { const version_t trim_max = g_conf().get_val("paxos_service_trim_max"); if (trim_max == 0 || to_remove < trim_max) { return to_remove; } if (to_remove < trim_max * 1.5) { - dout(10) << __func__ << " trim to " << get_trim_to() << " would only trim " << to_remove + dout(10) << __func__ << " trim to " << trim_to << " would only trim " << to_remove << " > paxos_service_trim_max, limiting to " << trim_max << dendl; return trim_max; @@ -412,11 +415,11 @@ return new_trim_max; } }(); - trim_to = get_first_committed() + to_remove; + trim_to = first_committed + to_remove; dout(10) << __func__ << " trimming to " << trim_to << ", " << to_remove << " states" << dendl; MonitorDBStore::TransactionRef t = paxos.get_pending_transaction(); - trim(t, get_first_committed(), trim_to); + trim(t, first_committed, trim_to); put_first_committed(t, trim_to); cached_first_committed = trim_to; diff -Nru ceph-16.2.5/src/mon/PGMap.cc ceph-16.2.6/src/mon/PGMap.cc --- ceph-16.2.5/src/mon/PGMap.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mon/PGMap.cc 2021-09-16 14:27:19.000000000 +0000 @@ -954,7 +954,11 @@ if (verbose) { f->dump_int("quota_objects", pool->quota_max_objects); f->dump_int("quota_bytes", pool->quota_max_bytes); - f->dump_int("dirty", sum.num_objects_dirty); + if (pool->is_tier()) { + f->dump_int("dirty", sum.num_objects_dirty); + } else { + f->dump_int("dirty", 0); + } f->dump_int("rd", sum.num_rd); f->dump_int("rd_bytes", sum.num_rd_kb * 1024ull); f->dump_int("wr", sum.num_wr); @@ -984,16 +988,17 @@ tbl << "N/A"; else tbl << stringify(si_u_t(pool->quota_max_objects)); - if (pool->quota_max_bytes == 0) tbl << "N/A"; else tbl << stringify(byte_u_t(pool->quota_max_bytes)); - - tbl << stringify(si_u_t(sum.num_objects_dirty)) - << stringify(byte_u_t(statfs.data_compressed_allocated)) - << stringify(byte_u_t(statfs.data_compressed_original)) - ; + if (pool->is_tier()) { + tbl << stringify(si_u_t(sum.num_objects_dirty)); + } else { + tbl << "N/A"; + } + tbl << stringify(byte_u_t(statfs.data_compressed_allocated)); + tbl << stringify(byte_u_t(statfs.data_compressed_original)); } } } diff -Nru ceph-16.2.5/src/msg/async/AsyncMessenger.h ceph-16.2.6/src/msg/async/AsyncMessenger.h --- ceph-16.2.5/src/msg/async/AsyncMessenger.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/msg/async/AsyncMessenger.h 2021-09-16 14:27:19.000000000 +0000 @@ -209,8 +209,6 @@ entity_addrvec_t _filter_addrs(const entity_addrvec_t& addrs); private: - static const uint64_t ReapDeadConnectionThreshold = 5; - NetworkStack *stack; std::vector processors; friend class Processor; @@ -404,7 +402,7 @@ deleted_conns.emplace(std::move(conn)); conn->unregister(); - if (deleted_conns.size() >= ReapDeadConnectionThreshold) { + if (deleted_conns.size() >= cct->_conf.get_val("ms_async_reap_threshold")) { local_worker->center.dispatch_event_external(reap_handler); } } diff -Nru ceph-16.2.5/src/msg/CMakeLists.txt ceph-16.2.6/src/msg/CMakeLists.txt --- ceph-16.2.5/src/msg/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/msg/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -38,6 +38,7 @@ endif() add_library(common-msg-objs OBJECT ${msg_srcs}) +compile_with_fmt(common-msg-objs) target_include_directories(common-msg-objs PRIVATE ${OPENSSL_INCLUDE_DIR}) if(WITH_DPDK) diff -Nru ceph-16.2.5/src/mypy.ini ceph-16.2.6/src/mypy.ini --- ceph-16.2.5/src/mypy.ini 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/mypy.ini 2021-09-16 14:27:19.000000000 +0000 @@ -40,6 +40,19 @@ [mypy-prometheus.*] disallow_untyped_defs = True +[mypy-pg_autoscaler.*] +disallow_untyped_defs = True + +[mypy-rbd_support.*] +disallow_untyped_defs = True + +[mypy-rook.*] +disallow_untyped_defs = True + +# external import +[mypy-rook.rook_client.*] +disallow_untyped_defs = False + # Make cephadm and rook happy [mypy-OpenSSL] ignore_missing_imports = True diff -Nru ceph-16.2.5/src/neorados/CMakeLists.txt ceph-16.2.6/src/neorados/CMakeLists.txt --- ceph-16.2.5/src/neorados/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/neorados/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -1,7 +1,9 @@ add_library(neorados_objs OBJECT RADOSImpl.cc) +compile_with_fmt(neorados_objs) add_library(neorados_api_obj OBJECT RADOS.cc) +compile_with_fmt(neorados_api_obj) add_library(libneorados STATIC $ diff -Nru ceph-16.2.5/src/os/bluestore/BlueFS.cc ceph-16.2.6/src/os/bluestore/BlueFS.cc --- ceph-16.2.5/src/os/bluestore/BlueFS.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/BlueFS.cc 2021-09-16 14:27:19.000000000 +0000 @@ -1152,18 +1152,27 @@ bl.claim_append(t); read_pos += r; } - seen_recs = true; bluefs_transaction_t t; try { auto p = bl.cbegin(); decode(t, p); + seen_recs = true; } catch (ceph::buffer::error& e) { - derr << __func__ << " 0x" << std::hex << pos << std::dec - << ": stop: failed to decode: " << e.what() - << dendl; - delete log_reader; - return -EIO; + // Multi-block transactions might be incomplete due to unexpected + // power off. Hence let's treat that as a regular stop condition. + if (seen_recs && more) { + dout(10) << __func__ << " 0x" << std::hex << pos << std::dec + << ": stop: failed to decode: " << e.what() + << dendl; + } else { + derr << __func__ << " 0x" << std::hex << pos << std::dec + << ": stop: failed to decode: " << e.what() + << dendl; + delete log_reader; + return -EIO; + } + break; } ceph_assert(seq == t.seq); dout(10) << __func__ << " 0x" << std::hex << pos << std::dec @@ -1421,6 +1430,9 @@ return r; } } + } else if (noop && fnode.ino == 1) { + FileRef f = _get_file(fnode.ino); + f->fnode = fnode; } } break; @@ -2680,6 +2692,33 @@ return bl; } +int BlueFS::_signal_dirty_to_log(FileWriter *h) +{ + h->file->fnode.mtime = ceph_clock_now(); + ceph_assert(h->file->fnode.ino >= 1); + if (h->file->dirty_seq == 0) { + h->file->dirty_seq = log_seq + 1; + dirty_files[h->file->dirty_seq].push_back(*h->file); + dout(20) << __func__ << " dirty_seq = " << log_seq + 1 + << " (was clean)" << dendl; + } else { + if (h->file->dirty_seq != log_seq + 1) { + // need re-dirty, erase from list first + ceph_assert(dirty_files.count(h->file->dirty_seq)); + auto it = dirty_files[h->file->dirty_seq].iterator_to(*h->file); + dirty_files[h->file->dirty_seq].erase(it); + h->file->dirty_seq = log_seq + 1; + dirty_files[h->file->dirty_seq].push_back(*h->file); + dout(20) << __func__ << " dirty_seq = " << log_seq + 1 + << " (was " << h->file->dirty_seq << ")" << dendl; + } else { + dout(20) << __func__ << " dirty_seq = " << log_seq + 1 + << " (unchanged, do nothing) " << dendl; + } + } + return 0; +} + int BlueFS::_flush_range(FileWriter *h, uint64_t offset, uint64_t length) { dout(10) << __func__ << " " << h << " pos 0x" << std::hex << h->pos @@ -2713,7 +2752,7 @@ vselector->sub_usage(h->file->vselector_hint, h->file->fnode); // do not bother to dirty the file if we are overwriting // previously allocated extents. - bool must_dirty = false; + if (allocated < offset + length) { // we should never run out of log space here; see the min runway check // in _flush_and_sync_log. @@ -2729,7 +2768,7 @@ ceph_abort_msg("bluefs enospc"); return r; } - must_dirty = true; + h->file->is_dirty = true; } if (h->file->fnode.size < offset + length) { h->file->fnode.size = offset + length; @@ -2737,34 +2776,10 @@ // we do not need to dirty the log file (or it's compacting // replacement) when the file size changes because replay is // smart enough to discover it on its own. - must_dirty = true; + h->file->is_dirty = true; } } - if (must_dirty) { - h->file->fnode.mtime = ceph_clock_now(); - ceph_assert(h->file->fnode.ino >= 1); - if (h->file->dirty_seq == 0) { - h->file->dirty_seq = log_seq + 1; - dirty_files[h->file->dirty_seq].push_back(*h->file); - dout(20) << __func__ << " dirty_seq = " << log_seq + 1 - << " (was clean)" << dendl; - } else { - if (h->file->dirty_seq != log_seq + 1) { - // need re-dirty, erase from list first - ceph_assert(dirty_files.count(h->file->dirty_seq)); - auto it = dirty_files[h->file->dirty_seq].iterator_to(*h->file); - dirty_files[h->file->dirty_seq].erase(it); - h->file->dirty_seq = log_seq + 1; - dirty_files[h->file->dirty_seq].push_back(*h->file); - dout(20) << __func__ << " dirty_seq = " << log_seq + 1 - << " (was " << h->file->dirty_seq << ")" << dendl; - } else { - dout(20) << __func__ << " dirty_seq = " << log_seq + 1 - << " (unchanged, do nothing) " << dendl; - } - } - } - dout(20) << __func__ << " file now " << h->file->fnode << dendl; + dout(20) << __func__ << " file now, unflushed " << h->file->fnode << dendl; uint64_t x_off = 0; auto p = h->file->fnode.seek(offset, &x_off); @@ -2956,6 +2971,10 @@ int r = _flush(h, true); if (r < 0) return r; + if (h->file->is_dirty) { + _signal_dirty_to_log(h); + h->file->is_dirty = false; + } uint64_t old_dirty_seq = h->file->dirty_seq; _flush_bdev_safely(h); @@ -3293,9 +3312,25 @@ } } } + // sanity + if (h->file->fnode.size >= (1ull << 30)) { + dout(10) << __func__ << " file is unexpectedly large:" << h->file->fnode << dendl; + } delete h; } +uint64_t BlueFS::debug_get_dirty_seq(FileWriter *h) +{ + std::lock_guard l(lock); + return h->file->dirty_seq; +} + +bool BlueFS::debug_get_is_dev_dirty(FileWriter *h, uint8_t dev) +{ + std::lock_guard l(lock); + return h->dirty_devs[dev]; +} + int BlueFS::open_for_read( std::string_view dirname, std::string_view filename, @@ -3802,7 +3837,9 @@ void OriginalVolumeSelector::get_paths(const std::string& base, paths& res) const { res.emplace_back(base, db_total); - res.emplace_back(base + ".slow", slow_total); + res.emplace_back(base + ".slow", + slow_total ? slow_total : db_total); // use fake non-zero value if needed to + // avoid RocksDB complains } #undef dout_prefix diff -Nru ceph-16.2.5/src/os/bluestore/BlueFS.h ceph-16.2.6/src/os/bluestore/BlueFS.h --- ceph-16.2.5/src/os/bluestore/BlueFS.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/BlueFS.h 2021-09-16 14:27:19.000000000 +0000 @@ -114,6 +114,7 @@ uint64_t dirty_seq; bool locked; bool deleted; + bool is_dirty; boost::intrusive::list_member_hook<> dirty_item; std::atomic_int num_readers, num_writers; @@ -129,6 +130,7 @@ dirty_seq(0), locked(false), deleted(false), + is_dirty(false), num_readers(0), num_writers(0), num_reading(0), @@ -384,6 +386,8 @@ int _allocate_without_fallback(uint8_t id, uint64_t len, PExtentVector* extents); + /* signal replay log to include h->file in nearest log flush */ + int _signal_dirty_to_log(FileWriter *h); int _flush_range(FileWriter *h, uint64_t offset, uint64_t length); int _flush(FileWriter *h, bool force, std::unique_lock& l); int _flush(FileWriter *h, bool force, bool *flushed = nullptr); @@ -640,6 +644,8 @@ const PerfCounters* get_perf_counters() const { return logger; } + uint64_t debug_get_dirty_seq(FileWriter *h); + bool debug_get_is_dev_dirty(FileWriter *h, uint8_t dev); private: // Wrappers for BlockDevice::read(...) and BlockDevice::read_random(...) diff -Nru ceph-16.2.5/src/os/bluestore/BlueRocksEnv.cc ceph-16.2.6/src/os/bluestore/BlueRocksEnv.cc --- ceph-16.2.5/src/os/bluestore/BlueRocksEnv.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/BlueRocksEnv.cc 2021-09-16 14:27:19.000000000 +0000 @@ -219,7 +219,7 @@ } rocksdb::Status Close() override { - fs->flush(h, true); + fs->fsync(h); // mimic posix env, here. shrug. size_t block_size; diff -Nru ceph-16.2.5/src/os/bluestore/BlueStore.cc ceph-16.2.6/src/os/bluestore/BlueStore.cc --- ceph-16.2.5/src/os/bluestore/BlueStore.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/BlueStore.cc 2021-09-16 14:27:19.000000000 +0000 @@ -542,6 +542,7 @@ return 0; } + template void _dump_extent_map(CephContext *cct, const BlueStore::ExtentMap &em) { @@ -3611,48 +3612,52 @@ extent_map.dump(f); } - -const string& BlueStore::Onode::get_omap_prefix() +const std::string& BlueStore::Onode::calc_omap_prefix(uint8_t flags) { - if (onode.is_pgmeta_omap()) { + if (bluestore_onode_t::is_pgmeta_omap(flags)) { return PREFIX_PGMETA_OMAP; } - if (onode.is_perpg_omap()) { + if (bluestore_onode_t::is_perpg_omap(flags)) { return PREFIX_PERPG_OMAP; } - if (onode.is_perpool_omap()) { + if (bluestore_onode_t::is_perpool_omap(flags)) { return PREFIX_PERPOOL_OMAP; } return PREFIX_OMAP; } // '-' < '.' < '~' - -void BlueStore::Onode::get_omap_header(string *out) -{ - if (!onode.is_pgmeta_omap()) { - if (onode.is_perpg_omap()) { - _key_encode_u64(c->pool(), out); - _key_encode_u32(oid.hobj.get_bitwise_key_u32(), out); - } else if (onode.is_perpool_omap()) { - _key_encode_u64(c->pool(), out); +void BlueStore::Onode::calc_omap_header( + uint8_t flags, + const Onode* o, + std::string* out) +{ + if (!bluestore_onode_t::is_pgmeta_omap(flags)) { + if (bluestore_onode_t::is_perpg_omap(flags)) { + _key_encode_u64(o->c->pool(), out); + _key_encode_u32(o->oid.hobj.get_bitwise_key_u32(), out); + } else if (bluestore_onode_t::is_perpool_omap(flags)) { + _key_encode_u64(o->c->pool(), out); } } - _key_encode_u64(onode.nid, out); + _key_encode_u64(o->onode.nid, out); out->push_back('-'); } -void BlueStore::Onode::get_omap_key(const string& key, string *out) -{ - if (!onode.is_pgmeta_omap()) { - if (onode.is_perpg_omap()) { - _key_encode_u64(c->pool(), out); - _key_encode_u32(oid.hobj.get_bitwise_key_u32(), out); - } else if (onode.is_perpool_omap()) { - _key_encode_u64(c->pool(), out); +void BlueStore::Onode::calc_omap_key(uint8_t flags, + const Onode* o, + const std::string& key, + std::string* out) +{ + if (!bluestore_onode_t::is_pgmeta_omap(flags)) { + if (bluestore_onode_t::is_perpg_omap(flags)) { + _key_encode_u64(o->c->pool(), out); + _key_encode_u32(o->oid.hobj.get_bitwise_key_u32(), out); + } else if (bluestore_onode_t::is_perpool_omap(flags)) { + _key_encode_u64(o->c->pool(), out); } } - _key_encode_u64(onode.nid, out); + _key_encode_u64(o->onode.nid, out); out->push_back('.'); out->append(key); } @@ -3671,17 +3676,20 @@ out->append(old.c_str() + out->length(), old.size() - out->length()); } -void BlueStore::Onode::get_omap_tail(string *out) -{ - if (!onode.is_pgmeta_omap()) { - if (onode.is_perpg_omap()) { - _key_encode_u64(c->pool(), out); - _key_encode_u32(oid.hobj.get_bitwise_key_u32(), out); - } else if (onode.is_perpool_omap()) { - _key_encode_u64(c->pool(), out); +void BlueStore::Onode::calc_omap_tail( + uint8_t flags, + const Onode* o, + std::string* out) +{ + if (!bluestore_onode_t::is_pgmeta_omap(flags)) { + if (bluestore_onode_t::is_perpg_omap(flags)) { + _key_encode_u64(o->c->pool(), out); + _key_encode_u32(o->oid.hobj.get_bitwise_key_u32(), out); + } else if (bluestore_onode_t::is_perpool_omap(flags)) { + _key_encode_u64(o->c->pool(), out); } } - _key_encode_u64(onode.nid, out); + _key_encode_u64(o->onode.nid, out); out->push_back('~'); } @@ -3698,7 +3706,6 @@ *user_key = key.substr(pos); } - // ======================================================= // WriteContext @@ -4977,7 +4984,10 @@ "Small writes into unused portion of existing blob"); b.add_u64_counter(l_bluestore_write_deferred, "bluestore_write_deferred", - "Overwrites using deferred"); + "Total deferred writes submitted"); + b.add_u64_counter(l_bluestore_write_deferred_bytes, + "bluestore_write_deferred_bytes", + "Total bytes submitted as deferred writes"); b.add_u64_counter(l_bluestore_write_small_pre_read, "bluestore_write_small_pre_read", "Small writes that required we read some data (possibly " @@ -6011,9 +6021,7 @@ BlueFSVolumeSelector::paths paths; bluefs->get_vselector_paths(fn, paths); - if (bluefs_layout.shared_bdev == BlueFS::BDEV_SLOW) { - // we have both block.db and block; tell rocksdb! - // note: the second (last) size value doesn't really matter + { ostringstream db_paths; bool first = true; for (auto& p : paths) { @@ -7249,7 +7257,7 @@ ++errors; } if (repairer) { - repairer->remove_key(db, PREFIX_SHARED_BLOB, key); + repairer->remove_key(db, PREFIX_STAT, key); } continue; } @@ -7816,12 +7824,71 @@ !o->onode.is_perpg_omap() && !o->onode.is_pgmeta_omap()) { dout(10) << "fsck converting " << o->oid << " omap to per-pg" << dendl; - bufferlist h; + bufferlist header; map kv; - int r = _onode_omap_get(o, &h, &kv); - if (r < 0) { - derr << " got " << r << " " << cpp_strerror(r) << dendl; - } else { + { + KeyValueDB::Transaction txn = db->get_transaction(); + uint64_t txn_cost = 0; + const string& prefix = Onode::calc_omap_prefix(o->onode.flags); + uint8_t new_flags = o->onode.flags | + bluestore_onode_t::FLAG_PERPOOL_OMAP | + bluestore_onode_t::FLAG_PERPG_OMAP; + const string& new_omap_prefix = Onode::calc_omap_prefix(new_flags); + + KeyValueDB::Iterator it = db->get_iterator(prefix); + string head, tail; + o->get_omap_header(&head); + o->get_omap_tail(&tail); + it->lower_bound(head); + // head + if (it->valid() && it->key() == head) { + dout(30) << __func__ << " got header" << dendl; + header = it->value(); + if (header.length()) { + string new_head; + Onode::calc_omap_header(new_flags, o.get(), &new_head); + txn->set(new_omap_prefix, new_head, header); + txn_cost += new_head.length() + header.length(); + } + } + // tail + { + string new_tail; + Onode::calc_omap_tail(new_flags, o.get(), &new_tail); + bufferlist empty; + txn->set(new_omap_prefix, new_tail, empty); + txn_cost += new_tail.length() + new_tail.length(); + } + // values + string final_key; + Onode::calc_omap_key(new_flags, o.get(), string(), &final_key); + size_t base_key_len = final_key.size(); + while (it->valid() && it->key() < tail) { + string user_key; + o->decode_omap_key(it->key(), &user_key); + dout(20) << __func__ << " got " << pretty_binary_string(it->key()) + << " -> " << user_key << dendl; + + final_key.resize(base_key_len); + final_key += it->key(); + auto v = it->value(); + txn->set(new_omap_prefix, final_key, v); + txn_cost += final_key.length() + v.length(); + + // submit a portion if cost exceeds 16MB + if (txn_cost >= 16 * (1 << 20) ) { + db->submit_transaction_sync(txn); + txn = db->get_transaction(); + txn_cost = 0; + } + it->next(); + } + if (txn_cost > 0) { + db->submit_transaction_sync(txn); + } + } + // finalize: remove legacy data + { KeyValueDB::Transaction txn = db->get_transaction(); // remove old keys const string& old_omap_prefix = o->get_omap_prefix(); @@ -7833,29 +7900,9 @@ // set flag o->onode.set_flag(bluestore_onode_t::FLAG_PERPOOL_OMAP | bluestore_onode_t::FLAG_PERPG_OMAP); _record_onode(o, txn); - const string& new_omap_prefix = o->get_omap_prefix(); - // head - if (h.length()) { - string new_head; - o->get_omap_header(&new_head); - txn->set(new_omap_prefix, new_head, h); - } - // tail - string new_tail; - o->get_omap_tail(&new_tail); - bufferlist empty; - txn->set(new_omap_prefix, new_tail, empty); - // values - string final_key; - o->get_omap_key(string(), &final_key); - size_t base_key_len = final_key.size(); - for (auto& i : kv) { - final_key.resize(base_key_len); - final_key += i.first; - txn->set(new_omap_prefix, final_key, i.second); - } db->submit_transaction_sync(txn); repairer->inc_repaired(); + repairer->request_compaction(); } } } @@ -12362,12 +12409,14 @@ } bluestore_deferred_op_t *BlueStore::_get_deferred_op( - TransContext *txc) + TransContext *txc, uint64_t len) { if (!txc->deferred_txn) { txc->deferred_txn = new bluestore_deferred_transaction_t; } txc->deferred_txn->ops.push_back(bluestore_deferred_op_t()); + logger->inc(l_bluestore_write_deferred); + logger->inc(l_bluestore_write_deferred_bytes, len); return &txc->deferred_txn->ops.back(); } @@ -13335,10 +13384,10 @@ wctx->buffered ? 0 : Buffer::FLAG_NOCACHE); if (!g_conf()->bluestore_debug_omit_block_device_write) { - if (b_len <= prefer_deferred_size) { + if (b_len < prefer_deferred_size) { dout(20) << __func__ << " deferring small 0x" << std::hex << b_len << std::dec << " unused write via deferred" << dendl; - bluestore_deferred_op_t *op = _get_deferred_op(txc); + bluestore_deferred_op_t *op = _get_deferred_op(txc, bl.length()); op->op = bluestore_deferred_op_t::OP_WRITE; b->get_blob().map( b_off, b_len, @@ -13426,7 +13475,7 @@ b->dirty_blob().calc_csum(b_off, bl); if (!g_conf()->bluestore_debug_omit_block_device_write) { - bluestore_deferred_op_t *op = _get_deferred_op(txc); + bluestore_deferred_op_t *op = _get_deferred_op(txc, bl.length()); op->op = bluestore_deferred_op_t::OP_WRITE; int r = b->get_blob().map( b_off, b_len, @@ -13446,7 +13495,6 @@ b->dirty_blob().mark_used(le->blob_offset, le->length); txc->statfs_delta.stored() += le->length; dout(20) << __func__ << " lex " << *le << dendl; - logger->inc(l_bluestore_write_deferred); return; } // try to reuse blob if we can @@ -13602,7 +13650,7 @@ ceph_assert(b_off % chunk_size == 0); ceph_assert(blob_aligned_len() % chunk_size == 0); - res = blob_aligned_len() <= prefer_deferred_size && + res = blob_aligned_len() < prefer_deferred_size && blob_aligned_len() <= ondisk && blob.is_allocated(b_off, blob_aligned_len()); if (res) { @@ -13688,7 +13736,7 @@ txc->statfs_delta.stored() += le->length; if (!g_conf()->bluestore_debug_omit_block_device_write) { - bluestore_deferred_op_t* op = _get_deferred_op(txc); + bluestore_deferred_op_t* op = _get_deferred_op(txc, bl.length()); op->op = bluestore_deferred_op_t::OP_WRITE; op->extents.swap(dctx.res_extents); op->data = std::move(bl); @@ -13713,14 +13761,22 @@ uint64_t prefer_deferred_size_snapshot = prefer_deferred_size.load(); while (length > 0) { bool new_blob = false; - uint32_t l = std::min(max_bsize, length); BlobRef b; uint32_t b_off = 0; + uint32_t l = 0; //attempting to reuse existing blob if (!wctx->compress) { + // enforce target blob alignment with max_bsize + l = max_bsize - p2phase(offset, max_bsize); + l = std::min(uint64_t(l), length); + auto end = o->extent_map.extent_map.end(); + dout(20) << __func__ << " may be defer: 0x" << std::hex + << offset << "~" << l + << std::dec << dendl; + if (prefer_deferred_size_snapshot && l <= prefer_deferred_size_snapshot * 2) { // Single write that spans two adjusted existing blobs can result @@ -13795,6 +13851,9 @@ _do_write_big_apply_deferred(txc, c, o, tail_info, blp, wctx); } + dout(20) << __func__ << " defer big: 0x" << std::hex + << offset << "~" << l + << std::dec << dendl; offset += l; length -= l; logger->inc(l_bluestore_write_big_blobs, remaining ? 2 : 1); @@ -13802,6 +13861,7 @@ continue; } } + dout(20) << __func__ << " lookup for blocks to reuse..." << dendl; o->extent_map.punch_hole(c, offset, l, &wctx->old_extents); @@ -13813,7 +13873,6 @@ prev_ep = ep; --prev_ep; } - dout(20) << __func__ << " no deferred" << dendl; auto min_off = offset >= max_bsize ? offset - max_bsize : 0; // search suitable extent in both forward and reverse direction in @@ -13823,9 +13882,8 @@ do { any_change = false; if (ep != end && ep->logical_offset < offset + max_bsize) { - dout(20) << __func__ << " considering " << *ep << dendl; - dout(20) << __func__ << " considering " << *(ep->blob) - << " bstart 0x" << std::hex << ep->blob_start() << std::dec << dendl; + dout(20) << __func__ << " considering " << *ep + << " bstart 0x" << std::hex << ep->blob_start() << std::dec << dendl; if (offset >= ep->blob_start() && ep->blob->can_reuse_blob(min_alloc_size, max_bsize, @@ -13843,9 +13901,8 @@ } if (prev_ep != end && prev_ep->logical_offset >= min_off) { - dout(20) << __func__ << " considering rev " << *prev_ep << dendl; - dout(20) << __func__ << " considering reverse " << *(prev_ep->blob) - << " bstart 0x" << std::hex << prev_ep->blob_start() << std::dec << dendl; + dout(20) << __func__ << " considering rev " << *prev_ep + << " bstart 0x" << std::hex << prev_ep->blob_start() << std::dec << dendl; if (prev_ep->blob->can_reuse_blob(min_alloc_size, max_bsize, offset - prev_ep->blob_start(), &l)) { @@ -13862,6 +13919,8 @@ } } while (b == nullptr && any_change); } else { + // trying to utilize as longer chunk as permitted in case of compression. + l = std::min(max_bsize, length); o->extent_map.punch_hole(c, offset, l, &wctx->old_extents); } // if (!wctx->compress) @@ -13873,6 +13932,10 @@ bufferlist t; blp.copy(l, t); wctx->write(offset, b, l, b_off, t, b_off, l, false, new_blob); + dout(20) << __func__ << " schedule write big: 0x" + << std::hex << offset << "~" << l << std::dec + << (new_blob ? " new " : " reuse ") + << *b << dendl; offset += l; length -= l; logger->inc(l_bluestore_write_big_blobs); @@ -14057,10 +14120,11 @@ dout(20) << __func__ << " prealloc " << prealloc << dendl; auto prealloc_pos = prealloc.begin(); + ceph_assert(prealloc_pos != prealloc.end()); + uint64_t prealloc_pos_length = prealloc_pos->length; for (auto& wi : wctx->writes) { - BlobRef b = wi.b; - bluestore_blob_t& dblob = b->dirty_blob(); + bluestore_blob_t& dblob = wi.b->dirty_blob(); uint64_t b_off = wi.b_off; bufferlist *l = &wi.bl; uint64_t final_length = wi.blob_length; @@ -14072,7 +14136,8 @@ l = &wi.compressed_bl; dblob.set_compressed(wi.blob_length, wi.compressed_len); if (csum != Checksummer::CSUM_NONE) { - dout(20) << __func__ << " initialize csum setting for compressed blob " << *b + dout(20) << __func__ + << " initialize csum setting for compressed blob " << *wi.b << " csum_type " << Checksummer::get_csum_type_string(csum) << " csum_order " << csum_order << " csum_length 0x" << std::hex << csum_length @@ -14107,7 +14172,8 @@ b_off = suggested_boff; } if (csum != Checksummer::CSUM_NONE) { - dout(20) << __func__ << " initialize csum setting for new blob " << *b + dout(20) << __func__ + << " initialize csum setting for new blob " << *wi.b << " csum_type " << Checksummer::get_csum_type_string(csum) << " csum_order " << csum_order << " csum_length 0x" << std::hex << csum_length << std::dec @@ -14118,14 +14184,20 @@ PExtentVector extents; int64_t left = final_length; + bool has_chunk2defer = false; + auto prefer_deferred_size_snapshot = prefer_deferred_size.load(); while (left > 0) { ceph_assert(prealloc_left > 0); + has_chunk2defer |= (prealloc_pos_length < prefer_deferred_size_snapshot); if (prealloc_pos->length <= left) { prealloc_left -= prealloc_pos->length; left -= prealloc_pos->length; txc->statfs_delta.allocated() += prealloc_pos->length; extents.push_back(*prealloc_pos); ++prealloc_pos; + if (prealloc_pos != prealloc.end()) { + prealloc_pos_length = prealloc_pos->length; + } } else { extents.emplace_back(prealloc_pos->offset, left); prealloc_pos->offset += left; @@ -14141,7 +14213,7 @@ } dblob.allocated(p2align(b_off, min_alloc_size), final_length, extents); - dout(20) << __func__ << " blob " << *b << dendl; + dout(20) << __func__ << " blob " << *wi.b << dendl; if (dblob.has_csum()) { dblob.calc_csum(b_off, *l); } @@ -14171,12 +14243,12 @@ // queue io if (!g_conf()->bluestore_debug_omit_block_device_write) { - if (l->length() <= prefer_deferred_size.load()) { + if (has_chunk2defer && l->length() < prefer_deferred_size_snapshot) { dout(20) << __func__ << " deferring 0x" << std::hex << l->length() << std::dec << " write via deferred" << dendl; - bluestore_deferred_op_t *op = _get_deferred_op(txc); + bluestore_deferred_op_t *op = _get_deferred_op(txc, l->length()); op->op = bluestore_deferred_op_t::OP_WRITE; - int r = b->get_blob().map( + int r = wi.b->get_blob().map( b_off, l->length(), [&](uint64_t offset, uint64_t length) { op->extents.emplace_back(bluestore_pextent_t(offset, length)); @@ -14184,9 +14256,8 @@ }); ceph_assert(r == 0); op->data = *l; - logger->inc(l_bluestore_write_deferred); } else { - b->get_blob().map_bl( + wi.b->get_blob().map_bl( b_off, *l, [&](uint64_t offset, bufferlist& t) { bdev->aio_write(offset, t, &txc->ioc, false); @@ -14981,7 +15052,7 @@ if (o->oid.is_pgmeta()) { o->onode.set_omap_flags_pgmeta(); } else { - o->onode.set_omap_flags(); + o->onode.set_omap_flags(per_pool_omap == OMAP_BULK); } txc->write_onode(o); @@ -15026,7 +15097,7 @@ if (o->oid.is_pgmeta()) { o->onode.set_omap_flags_pgmeta(); } else { - o->onode.set_omap_flags(); + o->onode.set_omap_flags(per_pool_omap == OMAP_BULK); } txc->write_onode(o); @@ -15182,7 +15253,7 @@ if (newo->oid.is_pgmeta()) { newo->onode.set_omap_flags_pgmeta(); } else { - newo->onode.set_omap_flags(); + newo->onode.set_omap_flags(per_pool_omap == OMAP_BULK); } const string& prefix = newo->get_omap_prefix(); KeyValueDB::Iterator it = db->get_iterator(prefix); @@ -16050,7 +16121,8 @@ { std::lock_guard l(qlock); - if (!spurious_read_errors_alert.empty()) { + if (!spurious_read_errors_alert.empty() && + cct->_conf->bluestore_warn_on_spurious_read_errors) { alerts.emplace( "BLUESTORE_SPURIOUS_READ_ERRORS", spurious_read_errors_alert); @@ -16351,6 +16423,10 @@ db->submit_transaction_sync(fix_statfs_txn); fix_statfs_txn = nullptr; } + if (need_compact) { + db->compact(); + need_compact = false; + } unsigned repaired = to_repair_cnt; to_repair_cnt = 0; return repaired; diff -Nru ceph-16.2.5/src/os/bluestore/BlueStore.h ceph-16.2.6/src/os/bluestore/BlueStore.h --- ceph-16.2.5/src/os/bluestore/BlueStore.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/BlueStore.h 2021-09-16 14:27:19.000000000 +0000 @@ -126,6 +126,7 @@ l_bluestore_write_small_bytes, l_bluestore_write_small_unused, l_bluestore_write_deferred, + l_bluestore_write_deferred_bytes, l_bluestore_write_small_pre_read, l_bluestore_write_new, l_bluestore_txc, @@ -1146,11 +1147,28 @@ return !pinned; } - const std::string& get_omap_prefix(); - void get_omap_header(std::string *out); - void get_omap_key(const std::string& key, std::string *out); + static const std::string& calc_omap_prefix(uint8_t flags); + static void calc_omap_header(uint8_t flags, const Onode* o, + std::string* out); + static void calc_omap_key(uint8_t flags, const Onode* o, + const std::string& key, std::string* out); + static void calc_omap_tail(uint8_t flags, const Onode* o, + std::string* out); + + const std::string& get_omap_prefix() { + return calc_omap_prefix(onode.flags); + } + void get_omap_header(std::string* out) { + calc_omap_header(onode.flags, this, out); + } + void get_omap_key(const std::string& key, std::string* out) { + calc_omap_key(onode.flags, this, key, out); + } + void get_omap_tail(std::string* out) { + calc_omap_tail(onode.flags, this, out); + } + void rewrite_omap_key(const std::string& old, std::string *out); - void get_omap_tail(std::string *out); void decode_omap_key(const std::string& key, std::string *user_key); // Return the offset of an object on disk. This function is intended *only* @@ -2486,7 +2504,7 @@ void _zoned_cleaner_thread(); void _zoned_clean_zone(uint64_t zone_num); - bluestore_deferred_op_t *_get_deferred_op(TransContext *txc); + bluestore_deferred_op_t *_get_deferred_op(TransContext *txc, uint64_t len); void _deferred_queue(TransContext *txc); public: void deferred_try_submit(); @@ -3650,10 +3668,15 @@ ++to_repair_cnt; } } - // In fact this is the only repairer's method which is thread-safe!! + ////////////////////// + //In fact two methods below are the only ones in this class which are thread-safe!! void inc_repaired() { ++to_repair_cnt; } + void request_compaction() { + need_compact = true; + } + ////////////////////// void init_space_usage_tracker( uint64_t total_space, uint64_t lres_tracking_unit_size) @@ -3686,6 +3709,7 @@ private: std::atomic to_repair_cnt = { 0 }; + std::atomic need_compact = { false }; KeyValueDB::Transaction fix_per_pool_omap_txn; KeyValueDB::Transaction fix_fm_leaked_txn; KeyValueDB::Transaction fix_fm_false_free_txn; diff -Nru ceph-16.2.5/src/os/bluestore/bluestore_tool.cc ceph-16.2.6/src/os/bluestore/bluestore_tool.cc --- ceph-16.2.5/src/os/bluestore/bluestore_tool.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/bluestore_tool.cc 2021-09-16 14:27:19.000000000 +0000 @@ -702,6 +702,7 @@ parse_devices(cct.get(), devs, &cur_devs_map, &has_db, &has_wal); + const char* rlpath = nullptr; if (has_db && has_wal) { cerr << "can't allocate new device, both WAL and DB exist" << std::endl; @@ -715,24 +716,35 @@ << std::endl; exit(EXIT_FAILURE); } else if(!dev_target.empty() && - realpath(dev_target.c_str(), target_path) == nullptr) { + (rlpath = realpath(dev_target.c_str(), target_path)) == nullptr) { cerr << "failed to retrieve absolute path for " << dev_target << ": " << cpp_strerror(errno) << std::endl; exit(EXIT_FAILURE); } - // Create either DB or WAL volume - int r = EXIT_FAILURE; - if (need_db && cct->_conf->bluestore_block_db_size == 0) { - cerr << "DB size isn't specified, " - "please set Ceph bluestore-block-db-size config parameter " - << std::endl; - } else if (!need_db && cct->_conf->bluestore_block_wal_size == 0) { - cerr << "WAL size isn't specified, " - "please set Ceph bluestore-block-wal-size config parameter " - << std::endl; - } else { + // Attach either DB or WAL volume, create if needed + struct stat st; + int r = -1; + if (rlpath != nullptr) { + r = ::stat(rlpath, &st); + } + // check if we need additional size specification + if (r == -1 || (r == 0 && S_ISREG(st.st_mode) && st.st_size == 0)) { + r = 0; + if (need_db && cct->_conf->bluestore_block_db_size == 0) { + cerr << "Might need DB size specification, " + "please set Ceph bluestore-block-db-size config parameter " + << std::endl; + r = EXIT_FAILURE; + } else if (!need_db && cct->_conf->bluestore_block_wal_size == 0) { + cerr << "Might need WAL size specification, " + "please set Ceph bluestore-block-wal-size config parameter " + << std::endl; + r = EXIT_FAILURE; + } + } + if (r == 0) { BlueStore bluestore(cct.get(), path); r = bluestore.add_new_bluefs_device( need_db ? BlueFS::BDEV_NEWDB : BlueFS::BDEV_NEWWAL, @@ -745,8 +757,8 @@ << cpp_strerror(r) << std::endl; } - return r; } + return r; } else if (action == "bluefs-bdev-migrate") { map cur_devs_map; set src_dev_ids; diff -Nru ceph-16.2.5/src/os/bluestore/bluestore_types.h ceph-16.2.6/src/os/bluestore/bluestore_types.h --- ceph-16.2.5/src/os/bluestore/bluestore_types.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/os/bluestore/bluestore_types.h 2021-09-16 14:27:19.000000000 +0000 @@ -999,6 +999,16 @@ bool has_omap() const { return has_flag(FLAG_OMAP); } + + static bool is_pgmeta_omap(uint8_t flags) { + return flags & FLAG_PGMETA_OMAP; + } + static bool is_perpool_omap(uint8_t flags) { + return flags & FLAG_PERPOOL_OMAP; + } + static bool is_perpg_omap(uint8_t flags) { + return flags & FLAG_PERPG_OMAP; + } bool is_pgmeta_omap() const { return has_flag(FLAG_PGMETA_OMAP); } @@ -1009,8 +1019,8 @@ return has_flag(FLAG_PERPG_OMAP); } - void set_omap_flags() { - set_flag(FLAG_OMAP | FLAG_PERPOOL_OMAP | FLAG_PERPG_OMAP); + void set_omap_flags(bool legacy) { + set_flag(FLAG_OMAP | (legacy ? 0 : (FLAG_PERPOOL_OMAP | FLAG_PERPG_OMAP))); } void set_omap_flags_pgmeta() { set_flag(FLAG_OMAP | FLAG_PGMETA_OMAP); diff -Nru ceph-16.2.5/src/osd/CMakeLists.txt ceph-16.2.6/src/osd/CMakeLists.txt --- ceph-16.2.5/src/osd/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -50,7 +50,7 @@ add_library(osd STATIC ${osd_srcs}) target_link_libraries(osd PUBLIC dmclock::dmclock Boost::MPL - PRIVATE os heap_profiler cpu_profiler ${CMAKE_DL_LIBS}) + PRIVATE os heap_profiler cpu_profiler fmt::fmt ${CMAKE_DL_LIBS}) if(WITH_LTTNG) add_dependencies(osd osd-tp pg-tp) endif() diff -Nru ceph-16.2.5/src/osd/osd_types.h ceph-16.2.6/src/osd/osd_types.h --- ceph-16.2.5/src/osd/osd_types.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/osd_types.h 2021-09-16 14:27:19.000000000 +0000 @@ -1596,12 +1596,12 @@ } int64_t get_dedup_tier() const { - int64_t tier_id; + int64_t tier_id = 0; opts.get(pool_opts_t::DEDUP_TIER, &tier_id); return tier_id; } int64_t get_dedup_cdc_chunk_size() const { - int64_t chunk_size; + int64_t chunk_size = 0; opts.get(pool_opts_t::DEDUP_CDC_CHUNK_SIZE, &chunk_size); return chunk_size; } diff -Nru ceph-16.2.5/src/osd/PeeringState.cc ceph-16.2.6/src/osd/PeeringState.cc --- ceph-16.2.5/src/osd/PeeringState.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/PeeringState.cc 2021-09-16 14:27:19.000000000 +0000 @@ -395,13 +395,23 @@ peer_missing.erase(p->first); peer_log_requested.erase(p->first); peer_missing_requested.erase(p->first); - peer_purged.erase(p->first); peer_info.erase(p++); removed = true; } else ++p; } + // Remove any downed osds from peer_purged so we can re-purge if necessary + auto it = peer_purged.begin(); + while (it != peer_purged.end()) { + if (!osdmap->is_up(it->osd)) { + psdout(10) << " dropping down osd." << *it << " from peer_purged" << dendl; + peer_purged.erase(it++); + } else { + ++it; + } + } + // if we removed anyone, update peers (which include peer_info) if (removed) update_heartbeat_peers(); diff -Nru ceph-16.2.5/src/osd/pg_scrubber.cc ceph-16.2.6/src/osd/pg_scrubber.cc --- ceph-16.2.5/src/osd/pg_scrubber.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/pg_scrubber.cc 2021-09-16 14:27:19.000000000 +0000 @@ -333,6 +333,7 @@ m_epoch_start = epoch_queued; m_needs_sleep = true; m_is_deep = state_test(PG_STATE_DEEP_SCRUB); + update_op_mode_text(); } unsigned int PgScrubber::scrub_requeue_priority(Scrub::scrub_prio_t with_priority) const @@ -744,6 +745,16 @@ return m_maps_status.dump(); } +void PgScrubber::update_op_mode_text() +{ + auto visible_repair = state_test(PG_STATE_REPAIR); + m_mode_desc = (visible_repair ? "repair"sv : (m_is_deep ? "deep-scrub"sv : "scrub"sv)); + + dout(10) << __func__ << ": repair: visible: " << (visible_repair ? "true" : "false") + << ", internal: " << (m_is_repair ? "true" : "false") + << ". Displayed: " << m_mode_desc << dendl; +} + void PgScrubber::_request_scrub_map(pg_shard_t replica, eversion_t version, hobject_t start, @@ -1133,8 +1144,15 @@ state_set(PG_STATE_DEEP_SCRUB); } - if (request.must_repair || m_flags.auto_repair) { + // m_is_repair is set for either 'must_repair' or 'repair-on-the-go' (i.e. + // deep-scrub with the auto_repair configuration flag set). m_is_repair value + // determines the scrubber behavior. + // PG_STATE_REPAIR, on the other hand, is only used for status reports (inc. the + // PG status as appearing in the logs). + m_is_repair = request.must_repair || m_flags.auto_repair; + if (request.must_repair) { state_set(PG_STATE_REPAIR); + // not calling update_op_mode_text() yet, as m_is_deep not set yet } // the publishing here seems to be required for tests synchronization @@ -1191,7 +1209,7 @@ ss.clear(); m_pg->get_pgbackend()->be_compare_scrubmaps( - maps, master_set, state_test(PG_STATE_REPAIR), m_missing, m_inconsistent, + maps, master_set, m_is_repair, m_missing, m_inconsistent, authoritative, missing_digest, m_shallow_errors, m_deep_errors, m_store.get(), m_pg->info.pgid, m_pg->recovery_state.get_acting(), ss); dout(2) << ss.str() << dendl; @@ -1228,7 +1246,7 @@ if (!m_store->empty()) { - if (state_test(PG_STATE_REPAIR)) { + if (m_is_repair) { dout(10) << __func__ << ": discarding scrub results" << dendl; m_store->flush(nullptr); } else { @@ -1439,25 +1457,25 @@ [[nodiscard]] bool PgScrubber::scrub_process_inconsistent() { - dout(10) << __func__ << ": checking authoritative" << dendl; - - bool repair = state_test(PG_STATE_REPAIR); - const bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); - const char* mode = (repair ? "repair" : (deep_scrub ? "deep-scrub" : "scrub")); - dout(20) << __func__ << " deep_scrub: " << deep_scrub << " m_is_deep: " << m_is_deep - << " repair: " << repair << dendl; + dout(10) << __func__ << ": checking authoritative (mode=" + << m_mode_desc << ", auth remaining #: " << m_authoritative.size() + << ")" << dendl; // authoritative only store objects which are missing or inconsistent. if (!m_authoritative.empty()) { stringstream ss; - ss << m_pg->info.pgid << " " << mode << " " << m_missing.size() << " missing, " + ss << m_pg->info.pgid << " " << m_mode_desc << " " << m_missing.size() << " missing, " << m_inconsistent.size() << " inconsistent objects"; dout(2) << ss.str() << dendl; m_osds->clog->error(ss); - if (repair) { + if (m_is_repair) { state_clear(PG_STATE_CLEAN); + // we know we have a problem, so it's OK to set the user-visible flag + // even if we only reached here via auto-repair + state_set(PG_STATE_REPAIR); + update_op_mode_text(); for (const auto& [hobj, shrd_list] : m_authoritative) { @@ -1475,7 +1493,7 @@ } } } - return (!m_authoritative.empty() && repair); + return (!m_authoritative.empty() && m_is_repair); } /* @@ -1492,24 +1510,21 @@ // if the repair request comes from auto-repair and large number of errors, // we would like to cancel auto-repair - - bool repair = state_test(PG_STATE_REPAIR); - if (repair && m_flags.auto_repair && + if (m_is_repair && m_flags.auto_repair && m_authoritative.size() > m_pg->cct->_conf->osd_scrub_auto_repair_num_errors) { dout(10) << __func__ << " undoing the repair" << dendl; - state_clear(PG_STATE_REPAIR); - repair = false; + state_clear(PG_STATE_REPAIR); // not expected to be set, anyway + m_is_repair = false; + update_op_mode_text(); } - bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); - const char* mode = (repair ? "repair" : (deep_scrub ? "deep-scrub" : "scrub")); bool do_auto_scrub = false; // if a regular scrub had errors within the limit, do a deep scrub to auto repair if (m_flags.deep_scrub_on_error && m_authoritative.size() && m_authoritative.size() <= m_pg->cct->_conf->osd_scrub_auto_repair_num_errors) { - ceph_assert(!deep_scrub); + ceph_assert(!m_is_deep); do_auto_scrub = true; dout(15) << __func__ << " Try to auto repair after scrub errors" << dendl; } @@ -1523,16 +1538,16 @@ { stringstream oss; - oss << m_pg->info.pgid.pgid << " " << mode << " "; + oss << m_pg->info.pgid.pgid << " " << m_mode_desc << " "; int total_errors = m_shallow_errors + m_deep_errors; if (total_errors) oss << total_errors << " errors"; else oss << "ok"; - if (!deep_scrub && m_pg->info.stats.stats.sum.num_deep_scrub_errors) + if (!m_is_deep && m_pg->info.stats.stats.sum.num_deep_scrub_errors) oss << " ( " << m_pg->info.stats.stats.sum.num_deep_scrub_errors << " remaining deep scrub error details lost)"; - if (repair) + if (m_is_repair) oss << ", " << m_fixed_count << " fixed"; if (total_errors) m_osds->clog->error(oss); @@ -1542,10 +1557,10 @@ // Since we don't know which errors were fixed, we can only clear them // when every one has been fixed. - if (repair) { + if (m_is_repair) { if (m_fixed_count == m_shallow_errors + m_deep_errors) { - ceph_assert(deep_scrub); + ceph_assert(m_is_deep); m_shallow_errors = 0; m_deep_errors = 0; dout(20) << __func__ << " All may be fixed" << dendl; @@ -1574,7 +1589,7 @@ // finish up ObjectStore::Transaction t; m_pg->recovery_state.update_stats( - [this, deep_scrub](auto& history, auto& stats) { + [this](auto& history, auto& stats) { dout(10) << "m_pg->recovery_state.update_stats()" << dendl; utime_t now = ceph_clock_now(); history.last_scrub = m_pg->recovery_state.get_info().last_update; @@ -1584,7 +1599,7 @@ history.last_deep_scrub_stamp = now; } - if (deep_scrub) { + if (m_is_deep) { if ((m_shallow_errors == 0) && (m_deep_errors == 0)) history.last_clean_scrub_stamp = now; stats.stats.sum.num_shallow_scrub_errors = m_shallow_errors; @@ -1628,7 +1643,9 @@ m_pg->queue_peering_event(PGPeeringEventRef(std::make_shared( get_osdmap_epoch(), get_osdmap_epoch(), PeeringState::DoRecovery()))); } else { + m_is_repair = false; state_clear(PG_STATE_REPAIR); + update_op_mode_text(); } cleanup_on_finish(); diff -Nru ceph-16.2.5/src/osd/pg_scrubber.h ceph-16.2.6/src/osd/pg_scrubber.h --- ceph-16.2.5/src/osd/pg_scrubber.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/pg_scrubber.h 2021-09-16 14:27:19.000000000 +0000 @@ -559,7 +559,7 @@ /// Maps from objects with errors to missing peers HobjToShardSetMapping m_missing; - private: + protected: /** * 'm_is_deep' - is the running scrub a deep one? * @@ -571,6 +571,33 @@ bool m_is_deep{false}; /** + * If set: affects the backend & scrubber-backend functions called after all + * scrub maps are available. + * + * Replaces code that directly checks PG_STATE_REPAIR (which was meant to be + * a "user facing" status display only). + */ + bool m_is_repair{false}; + + /** + * User-readable summary of the scrubber's current mode of operation. Used for + * both osd.*.log and the cluster log. + * One of: + * "repair" + * "deep-scrub", + * "scrub + * + * Note: based on PG_STATE_REPAIR, and not on m_is_repair. I.e. for + * auto_repair will show as "deep-scrub" and not as "repair" (until the first error + * is detected). + */ + std::string_view m_mode_desc; + + void update_op_mode_text(); + +private: + + /** * initiate a deep-scrub after the current scrub ended with errors. */ void request_rescrubbing(requested_scrub_t& req_flags); diff -Nru ceph-16.2.5/src/osd/PrimaryLogPG.cc ceph-16.2.6/src/osd/PrimaryLogPG.cc --- ceph-16.2.5/src/osd/PrimaryLogPG.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/PrimaryLogPG.cc 2021-09-16 14:27:19.000000000 +0000 @@ -4673,7 +4673,7 @@ ctx->mtime, 0) ); - derr << "removing snap head" << dendl; + dout(10) << "removing snap head" << dendl; object_info_t& oi = head_obc->obs.oi; ctx->delta_stats.num_objects--; if (oi.is_dirty()) { diff -Nru ceph-16.2.5/src/osd/PrimaryLogScrub.cc ceph-16.2.6/src/osd/PrimaryLogScrub.cc --- ceph-16.2.5/src/osd/PrimaryLogScrub.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/PrimaryLogScrub.cc 2021-09-16 14:27:19.000000000 +0000 @@ -47,10 +47,6 @@ << " info stats: " << (info.stats.stats_invalid ? "invalid" : "valid") << dendl; - bool repair = state_test(PG_STATE_REPAIR); - bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); - const char* mode = (repair ? "repair" : (deep_scrub ? "deep-scrub" : "scrub")); - if (info.stats.stats_invalid) { m_pl_pg->recovery_state.update_stats([=](auto& history, auto& stats) { stats.stats = m_scrub_cstat; @@ -62,7 +58,7 @@ m_pl_pg->agent_choose_mode(); } - dout(10) << mode << " got " << m_scrub_cstat.sum.num_objects << "/" + dout(10) << m_mode_desc << " got " << m_scrub_cstat.sum.num_objects << "/" << info.stats.stats.sum.num_objects << " objects, " << m_scrub_cstat.sum.num_object_clones << "/" << info.stats.stats.sum.num_object_clones << " clones, " @@ -100,7 +96,7 @@ !info.stats.manifest_stats_invalid) || m_scrub_cstat.sum.num_whiteouts != info.stats.stats.sum.num_whiteouts || m_scrub_cstat.sum.num_bytes != info.stats.stats.sum.num_bytes) { - m_osds->clog->error() << info.pgid << " " << mode << " : stat mismatch, got " + m_osds->clog->error() << info.pgid << " " << m_mode_desc << " : stat mismatch, got " << m_scrub_cstat.sum.num_objects << "/" << info.stats.stats.sum.num_objects << " objects, " << m_scrub_cstat.sum.num_object_clones << "/" @@ -125,7 +121,7 @@ << " hit_set_archive bytes."; ++m_shallow_errors; - if (repair) { + if (m_is_repair) { ++m_fixed_count; m_pl_pg->recovery_state.update_stats([this](auto& history, auto& stats) { stats.stats = m_scrub_cstat; @@ -142,7 +138,7 @@ } } // Clear object context cache to get repair information - if (repair) + if (m_is_repair) m_pl_pg->object_contexts.clear(); } @@ -157,15 +153,14 @@ LogChannelRef clog, const spg_t& pgid, const char* func, - const char* mode, bool allow_incomplete_clones) { ceph_assert(head); if (allow_incomplete_clones) { - dout(20) << func << " " << mode << " " << pgid << " " << *head << " skipped " + dout(20) << func << " " << m_mode_desc << " " << pgid << " " << *head << " skipped " << missing << " clone(s) in cache tier" << dendl; } else { - clog->info() << mode << " " << pgid << " " << *head << " : " << missing + clog->info() << m_mode_desc << " " << pgid << " " << *head << " : " << missing << " missing clone(s)"; } } @@ -174,7 +169,6 @@ const std::optional& snapset, LogChannelRef clog, const spg_t& pgid, - const char* mode, bool allow_incomplete_clones, std::optional target, vector::reverse_iterator* curclone, @@ -193,7 +187,7 @@ // skip higher-numbered clones in the list. if (!allow_incomplete_clones) { next_clone.snap = **curclone; - clog->error() << mode << " " << pgid << " " << *head << " : expected clone " + clog->error() << m_mode_desc << " " << pgid << " " << *head << " : expected clone " << next_clone << " " << m_missing << " missing"; ++m_shallow_errors; e.set_clone_missing(next_clone.snap); @@ -239,10 +233,6 @@ const PGPool& pool = m_pl_pg->pool; bool allow_incomplete_clones = pool.info.allow_incomplete_clones(); - bool repair = state_test(PG_STATE_REPAIR); - bool deep_scrub = state_test(PG_STATE_DEEP_SCRUB); - const char* mode = (repair ? "repair" : (deep_scrub ? "deep-scrub" : "scrub")); - std::optional all_clones; // Unspecified snapid_t or std::nullopt // traverse in reverse order. @@ -274,7 +264,7 @@ // basic checks. if (p->second.attrs.count(OI_ATTR) == 0) { oi = std::nullopt; - m_osds->clog->error() << mode << " " << info.pgid << " " << soid << " : no '" + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : no '" << OI_ATTR << "' attr"; ++m_shallow_errors; soid_error.set_info_missing(); @@ -286,7 +276,7 @@ oi->decode(bv); } catch (ceph::buffer::error& e) { oi = std::nullopt; - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : can't decode '" << OI_ATTR << "' attr " << e.what(); ++m_shallow_errors; soid_error.set_info_corrupted(); @@ -296,7 +286,7 @@ if (oi) { if (m_pl_pg->pgbackend->be_get_ondisk_size(oi->size) != p->second.size) { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : on disk size (" << p->second.size << ") does not match object info size (" << oi->size << ") adjusted for ondisk to (" @@ -305,7 +295,7 @@ ++m_shallow_errors; } - dout(20) << mode << " " << soid << " " << *oi << dendl; + dout(20) << m_mode_desc << " " << soid << " " << *oi << dendl; // A clone num_bytes will be added later when we have snapset if (!soid.is_snap()) { @@ -332,7 +322,7 @@ // Expecting an object with snap for current head if (soid.has_snapset() || soid.get_head() != head->get_head()) { - dout(10) << __func__ << " " << mode << " " << info.pgid << " new object " << soid + dout(10) << __func__ << " " << m_mode_desc << " " << info.pgid << " new object " << soid << " while processing " << *head << dendl; target = all_clones; @@ -344,7 +334,7 @@ // Log any clones we were expecting to be there up to target // This will set missing, but will be a no-op if snap.soid == *curclone. missing += - process_clones_to(head, snapset, m_osds->clog, info.pgid, mode, + process_clones_to(head, snapset, m_osds->clog, info.pgid, allow_incomplete_clones, target, &curclone, head_error); } @@ -364,10 +354,10 @@ if (!expected) { // If we couldn't read the head's snapset, just ignore clones if (head && !snapset) { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : clone ignored due to missing snapset"; } else { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : is an unexpected clone"; } ++m_shallow_errors; @@ -383,7 +373,7 @@ if (soid.has_snapset()) { if (missing) { - log_missing(missing, head, m_osds->clog, info.pgid, __func__, mode, + log_missing(missing, head, m_osds->clog, info.pgid, __func__, pool.info.allow_incomplete_clones()); } @@ -396,10 +386,10 @@ head_error = soid_error; soid_error_count = 0; - dout(20) << __func__ << " " << mode << " new head " << head << dendl; + dout(20) << __func__ << " " << m_mode_desc << " new head " << head << dendl; if (p->second.attrs.count(SS_ATTR) == 0) { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid << " : no '" + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : no '" << SS_ATTR << "' attr"; ++m_shallow_errors; snapset = std::nullopt; @@ -415,7 +405,7 @@ } catch (ceph::buffer::error& e) { snapset = std::nullopt; m_osds->clog->error() - << mode << " " << info.pgid << " " << soid << " : can't decode '" << SS_ATTR + << m_mode_desc << " " << info.pgid << " " << soid << " : can't decode '" << SS_ATTR << "' attr " << e.what(); ++m_shallow_errors; head_error.set_snapset_corrupted(); @@ -430,7 +420,7 @@ dout(20) << " snapset " << *snapset << dendl; if (snapset->seq == 0) { m_osds->clog->error() - << mode << " " << info.pgid << " " << soid << " : snaps.seq not set"; + << m_mode_desc << " " << info.pgid << " " << soid << " : snaps.seq not set"; ++m_shallow_errors; head_error.set_snapset_error(); } @@ -442,24 +432,24 @@ ceph_assert(snapset); ceph_assert(soid.snap == *curclone); - dout(20) << __func__ << " " << mode << " matched clone " << soid << dendl; + dout(20) << __func__ << " " << m_mode_desc << " matched clone " << soid << dendl; if (snapset->clone_size.count(soid.snap) == 0) { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : is missing in clone_size"; ++m_shallow_errors; soid_error.set_size_mismatch(); } else { if (oi && oi->size != snapset->clone_size[soid.snap]) { m_osds->clog->error() - << mode << " " << info.pgid << " " << soid << " : size " << oi->size + << m_mode_desc << " " << info.pgid << " " << soid << " : size " << oi->size << " != clone_size " << snapset->clone_size[*curclone]; ++m_shallow_errors; soid_error.set_size_mismatch(); } if (snapset->clone_overlap.count(soid.snap) == 0) { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : is missing in clone_overlap"; ++m_shallow_errors; soid_error.set_size_mismatch(); @@ -482,7 +472,7 @@ } if (bad_interval_set) { - m_osds->clog->error() << mode << " " << info.pgid << " " << soid + m_osds->clog->error() << m_mode_desc << " " << info.pgid << " " << soid << " : bad interval_set in clone_overlap"; ++m_shallow_errors; soid_error.set_size_mismatch(); @@ -503,18 +493,18 @@ } if (doing_clones(snapset, curclone)) { - dout(10) << __func__ << " " << mode << " " << info.pgid + dout(10) << __func__ << " " << m_mode_desc << " " << info.pgid << " No more objects while processing " << *head << dendl; missing += - process_clones_to(head, snapset, m_osds->clog, info.pgid, mode, + process_clones_to(head, snapset, m_osds->clog, info.pgid, allow_incomplete_clones, all_clones, &curclone, head_error); } // There could be missing found by the test above or even // before dropping out of the loop for the last head. if (missing) { - log_missing(missing, head, m_osds->clog, info.pgid, __func__, mode, + log_missing(missing, head, m_osds->clog, info.pgid, __func__, allow_incomplete_clones); } if (head && (head_error.errors || soid_error_count)) @@ -529,12 +519,12 @@ ObjectContextRef obc = m_pl_pg->get_object_context(p->first, false); if (!obc) { - m_osds->clog->error() << info.pgid << " " << mode + m_osds->clog->error() << info.pgid << " " << m_mode_desc << " cannot get object context for object " << p->first; continue; } if (obc->obs.oi.soid != p->first) { - m_osds->clog->error() << info.pgid << " " << mode << " " << p->first + m_osds->clog->error() << info.pgid << " " << m_mode_desc << " " << p->first << " : object has a valid oi attr with a mismatched name, " << " obc->obs.oi.soid: " << obc->obs.oi.soid; continue; @@ -565,7 +555,7 @@ m_pl_pg->simple_opc_submit(std::move(ctx)); } - dout(10) << __func__ << " (" << mode << ") finish" << dendl; + dout(10) << __func__ << " (" << m_mode_desc << ") finish" << dendl; } PrimaryLogScrub::PrimaryLogScrub(PrimaryLogPG* pg) : PgScrubber{pg}, m_pl_pg{pg} {} diff -Nru ceph-16.2.5/src/osd/PrimaryLogScrub.h ceph-16.2.6/src/osd/PrimaryLogScrub.h --- ceph-16.2.5/src/osd/PrimaryLogScrub.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osd/PrimaryLogScrub.h 2021-09-16 14:27:19.000000000 +0000 @@ -62,14 +62,12 @@ LogChannelRef clog, const spg_t& pgid, const char* func, - const char* mode, bool allow_incomplete_clones); int process_clones_to(const std::optional& head, const std::optional& snapset, LogChannelRef clog, const spg_t& pgid, - const char* mode, bool allow_incomplete_clones, std::optional target, std::vector::reverse_iterator* curclone, diff -Nru ceph-16.2.5/src/osdc/Objecter.cc ceph-16.2.6/src/osdc/Objecter.cc --- ceph-16.2.5/src/osdc/Objecter.cc 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osdc/Objecter.cc 2021-09-16 14:27:19.000000000 +0000 @@ -4722,6 +4722,13 @@ m->put(); } +Objecter::LingerOp::LingerOp(Objecter *o, uint64_t linger_id) + : objecter(o), + linger_id(linger_id), + watch_lock(ceph::make_shared_mutex( + fmt::format("LingerOp::watch_lock #{}", linger_id))) +{} + void Objecter::submit_command(CommandOp *c, ceph_tid_t *ptid) { shunique_lock sul(rwlock, ceph::acquire_unique); diff -Nru ceph-16.2.5/src/osdc/Objecter.h ceph-16.2.6/src/osdc/Objecter.h --- ceph-16.2.5/src/osdc/Objecter.h 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/osdc/Objecter.h 2021-09-16 14:27:19.000000000 +0000 @@ -2304,11 +2304,7 @@ watch_pending_async.pop_front(); } - explicit LingerOp(Objecter *o, uint64_t linger_id) - : objecter(o), linger_id(linger_id), - watch_lock(ceph::make_shared_mutex( - fmt::format("LingerOp::watch_lock #{}", linger_id))) {} - + LingerOp(Objecter *o, uint64_t linger_id); const LingerOp& operator=(const LingerOp& r) = delete; LingerOp(const LingerOp& o) = delete; diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/migrations.py ceph-16.2.6/src/pybind/mgr/cephadm/migrations.py --- ceph-16.2.5/src/pybind/mgr/cephadm/migrations.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/migrations.py 2021-09-16 14:27:19.000000000 +0000 @@ -93,6 +93,7 @@ placements, to_add, to_remove = HostAssignment( spec=spec, hosts=self.mgr.inventory.all_specs(), + unreachable_hosts=self.mgr._unreachable_hosts(), daemons=existing_daemons, ).place() diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/module.py ceph-16.2.6/src/pybind/mgr/cephadm/module.py --- ceph-16.2.5/src/pybind/mgr/cephadm/module.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/module.py 2021-09-16 14:27:19.000000000 +0000 @@ -91,12 +91,13 @@ """ # Default container images ----------------------------------------------------- -DEFAULT_IMAGE = 'docker.io/ceph/ceph' -DEFAULT_PROMETHEUS_IMAGE = 'docker.io/prom/prometheus:v2.18.1' -DEFAULT_NODE_EXPORTER_IMAGE = 'docker.io/prom/node-exporter:v0.18.1' -DEFAULT_GRAFANA_IMAGE = 'docker.io/ceph/ceph-grafana:6.7.4' -DEFAULT_ALERT_MANAGER_IMAGE = 'docker.io/prom/alertmanager:v0.20.0' +DEFAULT_IMAGE = 'quay.io/ceph/ceph' +DEFAULT_PROMETHEUS_IMAGE = 'quay.io/prometheus/prometheus:v2.18.1' +DEFAULT_NODE_EXPORTER_IMAGE = 'quay.io/prometheus/node-exporter:v0.18.1' +DEFAULT_ALERT_MANAGER_IMAGE = 'quay.io/prometheus/alertmanager:v0.20.0' +DEFAULT_GRAFANA_IMAGE = 'quay.io/ceph/ceph-grafana:6.7.4' DEFAULT_HAPROXY_IMAGE = 'docker.io/library/haproxy:2.3' +DEFAULT_KEEPALIVED_IMAGE = 'docker.io/arcts/keepalived' # ------------------------------------------------------------------------------ @@ -214,7 +215,7 @@ ), Option( 'container_image_keepalived', - default='arcts/keepalived', + default=DEFAULT_KEEPALIVED_IMAGE, desc='Keepalived container image', ), Option( @@ -466,6 +467,7 @@ self.template = TemplateMgr(self) self.requires_post_actions: Set[str] = set() + self.need_connect_dashboard_rgw = False self.config_checker = CephadmConfigChecks(self) @@ -1230,6 +1232,9 @@ @orchestrator._cli_read_command('orch client-keyring ls') def _client_keyring_ls(self, format: Format = Format.plain) -> HandleCommandResult: + """ + List client keyrings under cephadm management + """ if format != Format.plain: output = to_format(self.keys.keys.values(), format, many=True, cls=ClientKeyringSpec) else: @@ -1257,6 +1262,9 @@ owner: Optional[str] = None, mode: Optional[str] = None, ) -> HandleCommandResult: + """ + Add or update client keyring under cephadm management + """ if not entity.startswith('client.'): raise OrchestratorError('entity must start with client.') if owner: @@ -1285,6 +1293,9 @@ self, entity: str, ) -> HandleCommandResult: + """ + Remove client keyring from cephadm management + """ self.keys.rm(entity) self._kick_serve_loop() return HandleCommandResult() @@ -1381,11 +1392,27 @@ h for h in self.inventory.all_specs() if ( self.cache.host_had_daemon_refresh(h.hostname) - and h.status.lower() not in ['maintenance', 'offline'] and '_no_schedule' not in h.labels ) ] + def _unreachable_hosts(self) -> List[HostSpec]: + """ + Return all hosts that are offline or in maintenance mode. + + The idea is we should not touch the daemons on these hosts (since + in theory the hosts are inaccessible so we CAN'T touch them) but + we still want to count daemons that exist on these hosts toward the + placement so daemons on these hosts aren't just moved elsewhere + """ + return [ + h for h in self.inventory.all_specs() + if ( + h.status.lower() in ['maintenance', 'offline'] + or h.hostname in self.offline_hosts + ) + ] + def _check_valid_addr(self, host: str, addr: str) -> str: # make sure hostname is resolvable before trying to make a connection try: @@ -1456,19 +1483,80 @@ return self._add_host(spec) @handle_orch_error - def remove_host(self, host): - # type: (str) -> str + def remove_host(self, host: str, force: bool = False, offline: bool = False) -> str: """ Remove a host from orchestrator management. :param host: host name + :param force: bypass running daemons check + :param offline: remove offline host """ + + # check if host is offline + host_offline = host in self.offline_hosts + + if host_offline and not offline: + return "{} is offline, please use --offline and --force to remove this host. This can potentially cause data loss".format(host) + + if not host_offline and offline: + return "{} is online, please remove host without --offline.".format(host) + + if offline and not force: + return "Removing an offline host requires --force" + + # check if there are daemons on the host + if not force: + daemons = self.cache.get_daemons_by_host(host) + if daemons: + self.log.warning(f"Blocked {host} removal. Daemons running: {daemons}") + + daemons_table = "" + daemons_table += "{:<20} {:<15}\n".format("type", "id") + daemons_table += "{:<20} {:<15}\n".format("-" * 20, "-" * 15) + for d in daemons: + daemons_table += "{:<20} {:<15}\n".format(d.daemon_type, d.daemon_id) + + return "Not allowed to remove %s from cluster. " \ + "The following daemons are running in the host:" \ + "\n%s\nPlease run 'ceph orch host drain %s' to remove daemons from host" % ( + host, daemons_table, host) + + def run_cmd(cmd_args: dict) -> None: + ret, out, err = self.mon_command(cmd_args) + if ret != 0: + self.log.debug(f"ran {cmd_args} with mon_command") + self.log.error( + f"cmd: {cmd_args.get('prefix')} failed with: {err}. (errno:{ret})") + self.log.debug(f"cmd: {cmd_args.get('prefix')} returns: {out}") + + if offline: + daemons = self.cache.get_daemons_by_host(host) + for d in daemons: + self.log.info(f"removing: {d.name()}") + + if d.daemon_type != 'osd': + self.cephadm_services[str(d.daemon_type)].pre_remove(d) + self.cephadm_services[str(d.daemon_type)].post_remove(d) + else: + cmd_args = { + 'prefix': 'osd purge-actual', + 'id': int(str(d.daemon_id)), + 'yes_i_really_mean_it': True + } + run_cmd(cmd_args) + + cmd_args = { + 'prefix': 'osd crush rm', + 'name': host + } + run_cmd(cmd_args) + self.inventory.rm_host(host) self.cache.rm_host(host) self._reset_con(host) self.event.set() # refresh stray health check self.log.info('Removed host %s' % host) - return "Removed host '{}'".format(host) + return "Removed {} host '{}'".format('offline' if offline else '', host) @handle_orch_error def update_host_addr(self, host: str, addr: str) -> str: @@ -1634,7 +1722,7 @@ self._set_maintenance_healthcheck() - return f"Ceph cluster {self._cluster_fsid} on {hostname} moved to maintenance" + return f'Daemons for Ceph cluster {self._cluster_fsid} stopped on host {hostname}. Host {hostname} moved to maintenance mode' @handle_orch_error @host_exists() @@ -1820,6 +1908,8 @@ if not dds: raise OrchestratorError(f'No daemons exist under service name "{service_name}".' + ' View currently running services using "ceph orch ls"') + if action == 'stop' and service_name.split('.')[0].lower() in ['mgr', 'mon', 'osd']: + return [f'Stopping entire {service_name} service is prohibited.'] self.log.info('%s service %s' % (action.capitalize(), service_name)) return [ self._schedule_daemon_action(dd.name(), action) @@ -2215,7 +2305,7 @@ forcename=name) if not did_config: - self.cephadm_services[service_type].config(spec, daemon_id) + self.cephadm_services[service_type].config(spec) did_config = True daemon_spec = self.cephadm_services[service_type].make_daemon_spec( @@ -2273,6 +2363,7 @@ ha = HostAssignment( spec=spec, hosts=self._schedulable_hosts(), + unreachable_hosts=self._unreachable_hosts(), networks=self.cache.networks, daemons=self.cache.get_daemons_by_service(spec.service_name()), allow_colo=svc.allow_colo(), @@ -2348,6 +2439,7 @@ HostAssignment( spec=spec, hosts=self.inventory.all_specs(), # All hosts, even those without daemon refresh + unreachable_hosts=self._unreachable_hosts(), networks=self.cache.networks, daemons=self.cache.get_daemons_by_service(spec.service_name()), allow_colo=self.cephadm_services[spec.service_type].allow_colo(), @@ -2564,3 +2656,29 @@ The CLI call to retrieve an osd removal report """ return self.to_remove_osds.all_osds() + + @handle_orch_error + def drain_host(self, hostname): + # type: (str) -> str + """ + Drain all daemons from a host. + :param host: host name + """ + self.add_host_label(hostname, '_no_schedule') + + daemons: List[orchestrator.DaemonDescription] = self.cache.get_daemons_by_host(hostname) + + osds_to_remove = [d.daemon_id for d in daemons if d.daemon_type == 'osd'] + self.remove_osds(osds_to_remove) + + daemons_table = "" + daemons_table += "{:<20} {:<15}\n".format("type", "id") + daemons_table += "{:<20} {:<15}\n".format("-" * 20, "-" * 15) + for d in daemons: + daemons_table += "{:<20} {:<15}\n".format(d.daemon_type, d.daemon_id) + + return "Scheduled to remove the following daemons from host '{}'\n{}".format(hostname, daemons_table) + + def trigger_connect_dashboard_rgw(self) -> None: + self.need_connect_dashboard_rgw = True + self.event.set() diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/schedule.py ceph-16.2.6/src/pybind/mgr/cephadm/schedule.py --- ceph-16.2.5/src/pybind/mgr/cephadm/schedule.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/schedule.py 2021-09-16 14:27:19.000000000 +0000 @@ -141,6 +141,7 @@ def __init__(self, spec, # type: ServiceSpec hosts: List[orchestrator.HostSpec], + unreachable_hosts: List[orchestrator.HostSpec], daemons: List[orchestrator.DaemonDescription], networks: Dict[str, Dict[str, Dict[str, List[str]]]] = {}, filter_new_host=None, # type: Optional[Callable[[str],bool]] @@ -153,6 +154,7 @@ self.spec = spec # type: ServiceSpec self.primary_daemon_type = primary_daemon_type or spec.service_type self.hosts: List[orchestrator.HostSpec] = hosts + self.unreachable_hosts: List[orchestrator.HostSpec] = unreachable_hosts self.filter_new_host = filter_new_host self.service_name = spec.service_name() self.daemons = daemons @@ -231,6 +233,9 @@ to_remove.append(dd) to_add += host_slots + to_remove = [d for d in to_remove if d.hostname not in [ + h.hostname for h in self.unreachable_hosts]] + return slots, to_add, to_remove def place(self): @@ -286,6 +291,7 @@ existing_active: List[orchestrator.DaemonDescription] = [] existing_standby: List[orchestrator.DaemonDescription] = [] existing_slots: List[DaemonPlacement] = [] + to_add: List[DaemonPlacement] = [] to_remove: List[orchestrator.DaemonDescription] = [] ranks: List[int] = list(range(len(candidates))) others: List[DaemonPlacement] = candidates.copy() @@ -308,11 +314,17 @@ if not found: to_remove.append(dd) + # TODO: At some point we want to deploy daemons that are on offline hosts + # at what point we do this differs per daemon type. Stateless daemons we could + # do quickly to improve availability. Steful daemons we might want to wait longer + # to see if the host comes back online + existing = existing_active + existing_standby # build to_add if not count: - to_add = others + to_add = [dd for dd in others if dd.hostname not in [ + h.hostname for h in self.unreachable_hosts]] else: # The number of new slots that need to be selected in order to fulfill count need = count - len(existing) @@ -323,8 +335,12 @@ del existing_slots[count:] return self.place_per_host_daemons(existing_slots, [], to_remove) - if need > 0: - to_add = others[:need] + for dp in others: + if need <= 0: + break + if dp.hostname not in [h.hostname for h in self.unreachable_hosts]: + to_add.append(dp) + need -= 1 # this is last use of need in this function so it can work as a counter if self.rank_map is not None: # assign unused ranks (and rank_generations) to to_add diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/serve.py ceph-16.2.6/src/pybind/mgr/cephadm/serve.py --- ceph-16.2.5/src/pybind/mgr/cephadm/serve.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/serve.py 2021-09-16 14:27:19.000000000 +0000 @@ -38,6 +38,8 @@ logger = logging.getLogger(__name__) +REQUIRES_POST_ACTIONS = ['grafana', 'iscsi', 'prometheus', 'alertmanager', 'rgw'] + class CephadmServe: """ @@ -79,6 +81,12 @@ self._update_paused_health() + if self.mgr.need_connect_dashboard_rgw and self.mgr.config_dashboard: + self.mgr.need_connect_dashboard_rgw = False + if 'dashboard' in self.mgr.get('mgr_map')['modules']: + self.log.info('Checking dashboard <-> RGW credentials') + self.mgr.remote('dashboard', 'set_rgw_credentials') + if not self.mgr.paused: self.mgr.to_remove_osds.process_removal_queue() @@ -194,6 +202,7 @@ ha = HostAssignment( spec=ServiceSpec('mon', placement=pspec), hosts=self.mgr._schedulable_hosts(), + unreachable_hosts=self.mgr._unreachable_hosts(), daemons=[], networks=self.mgr.cache.networks, ) @@ -225,6 +234,7 @@ ha = HostAssignment( spec=ServiceSpec('mon', placement=ks.placement), hosts=self.mgr._schedulable_hosts(), + unreachable_hosts=self.mgr._unreachable_hosts(), daemons=[], networks=self.mgr.cache.networks, ) @@ -368,20 +378,21 @@ return None self.log.debug(' checking %s' % host) try: + addr = self.mgr.inventory.get_addr(host) if host in self.mgr.inventory else host out, err, code = self._run_cephadm( host, cephadmNoImage, 'check-host', [], error_ok=True, no_fsid=True) self.mgr.cache.update_last_host_check(host) self.mgr.cache.save_host(host) if code: - self.log.debug(' host %s failed check' % host) + self.log.debug(' host %s (%s) failed check' % (host, addr)) if self.mgr.warn_on_failed_host_check: - return 'host %s failed check: %s' % (host, err) + return 'host %s (%s) failed check: %s' % (host, addr, err) else: - self.log.debug(' host %s ok' % host) + self.log.debug(' host %s (%s) ok' % (host, addr)) except Exception as e: - self.log.debug(' host %s failed check' % host) - return 'host %s failed check: %s' % (host, e) + self.log.debug(' host %s (%s) failed check' % (host, addr)) + return 'host %s (%s) failed check: %s' % (host, addr, e) return None def _refresh_host_daemons(self, host: str) -> Optional[str]: @@ -404,6 +415,10 @@ if v: setattr(sd, k, str_to_datetime(d[k])) sd.daemon_type = d['name'].split('.')[0] + if sd.daemon_type not in orchestrator.KNOWN_DAEMON_TYPES: + logger.warning(f"Found unknown daemon type {sd.daemon_type} on host {host}") + continue + sd.daemon_id = '.'.join(d['name'].split('.')[1:]) sd.hostname = host sd.container_id = d.get('container_id') @@ -422,7 +437,8 @@ sd.ports = d.get('ports') sd.ip = d.get('ip') sd.rank = int(d['rank']) if d.get('rank') is not None else None - sd.rank_generation = int(d['rank_generation']) if d.get('rank_generation') is not None else None + sd.rank_generation = int(d['rank_generation']) if d.get( + 'rank_generation') is not None else None if sd.daemon_type == 'osd': sd.osdspec_affinity = self.mgr.osd_service.get_osdspec_affinity(sd.daemon_id) if 'state' in d: @@ -671,6 +687,7 @@ ha = HostAssignment( spec=spec, hosts=self.mgr._schedulable_hosts(), + unreachable_hosts=self.mgr._unreachable_hosts(), daemons=daemons, networks=self.mgr.cache.networks, filter_new_host=( @@ -686,7 +703,7 @@ try: all_slots, slots_to_add, daemons_to_remove = ha.place() daemons_to_remove = [d for d in daemons_to_remove if (d.hostname and self.mgr.inventory._inventory[d.hostname].get( - 'status', '').lower() not in ['maintenance', 'offline'])] + 'status', '').lower() not in ['maintenance', 'offline'] and d.hostname not in self.mgr.offline_hosts)] self.log.debug('Add %s, remove %s' % (slots_to_add, daemons_to_remove)) except OrchestratorError as e: self.log.error('Failed to apply %s spec %s: %s' % ( @@ -730,124 +747,128 @@ self.log.debug('Hosts that will receive new daemons: %s' % slots_to_add) self.log.debug('Daemons that will be removed: %s' % daemons_to_remove) - # assign names - for i in range(len(slots_to_add)): - slot = slots_to_add[i] - slot = slot.assign_name(self.mgr.get_unique_name( - slot.daemon_type, - slot.hostname, - daemons, - prefix=spec.service_id, - forcename=slot.name, - rank=slot.rank, - rank_generation=slot.rank_generation, - )) - slots_to_add[i] = slot - if rank_map is not None: - assert slot.rank is not None - assert slot.rank_generation is not None - assert rank_map[slot.rank][slot.rank_generation] is None - rank_map[slot.rank][slot.rank_generation] = slot.name - - if rank_map: - # record the rank_map before we make changes so that if we fail the - # next mgr will clean up. - self.mgr.spec_store.save_rank_map(spec.service_name(), rank_map) - - # remove daemons now, since we are going to fence them anyway - for d in daemons_to_remove: - assert d.hostname is not None - self._remove_daemon(d.name(), d.hostname) - daemons_to_remove = [] - - # fence them - svc.fence_old_ranks(spec, rank_map, len(all_slots)) + try: + # assign names + for i in range(len(slots_to_add)): + slot = slots_to_add[i] + slot = slot.assign_name(self.mgr.get_unique_name( + slot.daemon_type, + slot.hostname, + daemons, + prefix=spec.service_id, + forcename=slot.name, + rank=slot.rank, + rank_generation=slot.rank_generation, + )) + slots_to_add[i] = slot + if rank_map is not None: + assert slot.rank is not None + assert slot.rank_generation is not None + assert rank_map[slot.rank][slot.rank_generation] is None + rank_map[slot.rank][slot.rank_generation] = slot.name + + if rank_map: + # record the rank_map before we make changes so that if we fail the + # next mgr will clean up. + self.mgr.spec_store.save_rank_map(spec.service_name(), rank_map) - # create daemons - for slot in slots_to_add: - # first remove daemon on conflicting port? - if slot.ports: + # remove daemons now, since we are going to fence them anyway for d in daemons_to_remove: - if d.hostname != slot.hostname: - continue - if not (set(d.ports or []) & set(slot.ports)): - continue - if d.ip and slot.ip and d.ip != slot.ip: - continue - self.log.info( - f'Removing {d.name()} before deploying to {slot} to avoid a port conflict' - ) - # NOTE: we don't check ok-to-stop here to avoid starvation if - # there is only 1 gateway. + assert d.hostname is not None self._remove_daemon(d.name(), d.hostname) - daemons_to_remove.remove(d) + daemons_to_remove = [] + + # fence them + svc.fence_old_ranks(spec, rank_map, len(all_slots)) + + # create daemons + for slot in slots_to_add: + # first remove daemon on conflicting port? + if slot.ports: + for d in daemons_to_remove: + if d.hostname != slot.hostname: + continue + if not (set(d.ports or []) & set(slot.ports)): + continue + if d.ip and slot.ip and d.ip != slot.ip: + continue + self.log.info( + f'Removing {d.name()} before deploying to {slot} to avoid a port conflict' + ) + # NOTE: we don't check ok-to-stop here to avoid starvation if + # there is only 1 gateway. + self._remove_daemon(d.name(), d.hostname) + daemons_to_remove.remove(d) + progress_done += 1 + break + + # deploy new daemon + daemon_id = slot.name + if not did_config: + svc.config(spec) + did_config = True + + daemon_spec = svc.make_daemon_spec( + slot.hostname, daemon_id, slot.network, spec, + daemon_type=slot.daemon_type, + ports=slot.ports, + ip=slot.ip, + rank=slot.rank, + rank_generation=slot.rank_generation, + ) + self.log.debug('Placing %s.%s on host %s' % ( + slot.daemon_type, daemon_id, slot.hostname)) + + try: + daemon_spec = svc.prepare_create(daemon_spec) + self._create_daemon(daemon_spec) + r = True + progress_done += 1 + update_progress() + except (RuntimeError, OrchestratorError) as e: + msg = (f"Failed while placing {slot.daemon_type}.{daemon_id} " + f"on {slot.hostname}: {e}") + self.mgr.events.for_service(spec, 'ERROR', msg) + self.mgr.log.error(msg) + # only return "no change" if no one else has already succeeded. + # later successes will also change to True + if r is None: + r = False progress_done += 1 - break + update_progress() + continue - # deploy new daemon - daemon_id = slot.name - if not did_config: - svc.config(spec, daemon_id) - did_config = True - - daemon_spec = svc.make_daemon_spec( - slot.hostname, daemon_id, slot.network, spec, - daemon_type=slot.daemon_type, - ports=slot.ports, - ip=slot.ip, - rank=slot.rank, - rank_generation=slot.rank_generation, - ) - self.log.debug('Placing %s.%s on host %s' % ( - slot.daemon_type, daemon_id, slot.hostname)) + # add to daemon list so next name(s) will also be unique + sd = orchestrator.DaemonDescription( + hostname=slot.hostname, + daemon_type=slot.daemon_type, + daemon_id=daemon_id, + ) + daemons.append(sd) - try: - daemon_spec = svc.prepare_create(daemon_spec) - self._create_daemon(daemon_spec) + # remove any? + def _ok_to_stop(remove_daemons: List[orchestrator.DaemonDescription]) -> bool: + daemon_ids = [d.daemon_id for d in remove_daemons] + assert None not in daemon_ids + # setting force flag retains previous behavior + r = svc.ok_to_stop(cast(List[str], daemon_ids), force=True) + return not r.retval + + while daemons_to_remove and not _ok_to_stop(daemons_to_remove): + # let's find a subset that is ok-to-stop + daemons_to_remove.pop() + for d in daemons_to_remove: r = True + assert d.hostname is not None + self._remove_daemon(d.name(), d.hostname) + progress_done += 1 update_progress() - except (RuntimeError, OrchestratorError) as e: - msg = (f"Failed while placing {slot.daemon_type}.{daemon_id} " - f"on {slot.hostname}: {e}") - self.mgr.events.for_service(spec, 'ERROR', msg) - self.mgr.log.error(msg) - # only return "no change" if no one else has already succeeded. - # later successes will also change to True - if r is None: - r = False - progress_done += 1 - update_progress() - continue - - # add to daemon list so next name(s) will also be unique - sd = orchestrator.DaemonDescription( - hostname=slot.hostname, - daemon_type=slot.daemon_type, - daemon_id=daemon_id, - ) - daemons.append(sd) - - # remove any? - def _ok_to_stop(remove_daemons: List[orchestrator.DaemonDescription]) -> bool: - daemon_ids = [d.daemon_id for d in remove_daemons] - assert None not in daemon_ids - # setting force flag retains previous behavior - r = svc.ok_to_stop(cast(List[str], daemon_ids), force=True) - return not r.retval - - while daemons_to_remove and not _ok_to_stop(daemons_to_remove): - # let's find a subset that is ok-to-stop - daemons_to_remove.pop() - for d in daemons_to_remove: - r = True - assert d.hostname is not None - self._remove_daemon(d.name(), d.hostname) - progress_done += 1 - update_progress() - - self.mgr.remote('progress', 'complete', progress_id) + self.mgr.remote('progress', 'complete', progress_id) + except Exception as e: + self.mgr.remote('progress', 'fail', progress_id, str(e)) + raise if r is None: r = False @@ -878,7 +899,7 @@ continue # These daemon types require additional configs after creation - if dd.daemon_type in ['grafana', 'iscsi', 'prometheus', 'alertmanager', 'nfs']: + if dd.daemon_type in REQUIRES_POST_ACTIONS: daemons_post[dd.daemon_type].append(dd) if self.mgr.cephadm_services[daemon_type_to_service(dd.daemon_type)].get_active_daemon( @@ -1055,9 +1076,7 @@ sd = daemon_spec.to_daemon_description( DaemonDescriptionStatus.running, 'starting') self.mgr.cache.add_daemon(daemon_spec.host, sd) - if daemon_spec.daemon_type in [ - 'grafana', 'iscsi', 'prometheus', 'alertmanager' - ]: + if daemon_spec.daemon_type in REQUIRES_POST_ACTIONS: self.mgr.requires_post_actions.add(daemon_spec.daemon_type) self.mgr.cache.invalidate_host_daemons(daemon_spec.host) diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/services/cephadmservice.py ceph-16.2.6/src/pybind/mgr/cephadm/services/cephadmservice.py --- ceph-16.2.5/src/pybind/mgr/cephadm/services/cephadmservice.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/services/cephadmservice.py 2021-09-16 14:27:19.000000000 +0000 @@ -188,7 +188,7 @@ def generate_config(self, daemon_spec: CephadmDaemonDeploySpec) -> Tuple[Dict[str, Any], List[str]]: raise NotImplementedError() - def config(self, spec: ServiceSpec, daemon_id: str) -> None: + def config(self, spec: ServiceSpec) -> None: """ Configure the cluster for this service. Only called *once* per service apply. Not for every daemon. @@ -701,7 +701,7 @@ def allow_colo(self) -> bool: return True - def config(self, spec: ServiceSpec, daemon_id: str) -> None: + def config(self, spec: ServiceSpec) -> None: assert self.TYPE == spec.service_type assert spec.service_id @@ -757,7 +757,7 @@ def allow_colo(self) -> bool: return True - def config(self, spec: RGWSpec, rgw_id: str) -> None: # type: ignore + def config(self, spec: RGWSpec) -> None: # type: ignore assert self.TYPE == spec.service_type # set rgw_realm and rgw_zone, if present @@ -795,6 +795,7 @@ logger.info('Saving service %s spec with placement %s' % ( spec.service_name(), spec.placement.pretty_str())) self.mgr.spec_store.save(spec) + self.mgr.trigger_connect_dashboard_rgw() def prepare_create(self, daemon_spec: CephadmDaemonDeploySpec) -> CephadmDaemonDeploySpec: assert self.TYPE == daemon_spec.daemon_type @@ -874,6 +875,7 @@ 'prefix': 'config-key rm', 'key': f'rgw/cert/{service_name}', }) + self.mgr.trigger_connect_dashboard_rgw() def post_remove(self, daemon: DaemonDescription) -> None: super().post_remove(daemon) @@ -918,6 +920,9 @@ warn_message = "WARNING: Removing RGW daemons can cause clients to lose connectivity. " return HandleCommandResult(-errno.EBUSY, '', warn_message) + def config_dashboard(self, daemon_descrs: List[DaemonDescription]) -> None: + self.mgr.trigger_connect_dashboard_rgw() + class RbdMirrorService(CephService): TYPE = 'rbd-mirror' diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/services/ingress.py ceph-16.2.6/src/pybind/mgr/cephadm/services/ingress.py --- ceph-16.2.5/src/pybind/mgr/cephadm/services/ingress.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/services/ingress.py 2021-09-16 14:27:19.000000000 +0000 @@ -5,6 +5,7 @@ from typing import List, Dict, Any, Tuple, cast, Optional from ceph.deployment.service_spec import IngressSpec +from mgr_util import build_url from cephadm.utils import resolve_ip from orchestrator import OrchestratorError from cephadm.services.cephadmservice import CephadmDaemonDeploySpec, CephService @@ -65,7 +66,8 @@ spec = cast(IngressSpec, self.mgr.spec_store[daemon_spec.service_name].spec) assert spec.backend_service if spec.backend_service not in self.mgr.spec_store: - raise RuntimeError(f'{spec.service_name()} backend service {spec.backend_service} does not exist') + raise RuntimeError( + f'{spec.service_name()} backend service {spec.backend_service} does not exist') backend_spec = self.mgr.spec_store[spec.backend_service].spec daemons = self.mgr.cache.get_daemons_by_service(spec.backend_service) deps = [d.name() for d in daemons] @@ -183,6 +185,11 @@ password = spec.keepalived_password daemons = self.mgr.cache.get_daemons_by_service(spec.service_name()) + + if not daemons: + raise OrchestratorError( + f'Failed to generate keepalived.conf: No daemons deployed for {spec.service_name()}') + deps = sorted([d.name() for d in daemons if d.daemon_type == 'haproxy']) host = daemon_spec.host @@ -198,10 +205,10 @@ f'{bare_ip} is in {subnet} on {host} interface {interface}' ) break - if not interface and spec.networks: - # hmm, try spec.networks + # try to find interface by matching spec.virtual_interface_networks + if not interface and spec.virtual_interface_networks: for subnet, ifaces in self.mgr.cache.networks.get(host, {}).items(): - if subnet in spec.networks: + if subnet in spec.virtual_interface_networks: interface = list(ifaces.keys())[0] logger.info( f'{spec.virtual_ip} will be configured on {host} interface ' @@ -220,7 +227,7 @@ if d.daemon_type == 'haproxy': assert d.ports port = d.ports[1] # monitoring port - script = f'/usr/bin/curl http://{d.ip or "localhost"}:{port}/health' + script = f'/usr/bin/curl {build_url(scheme="http", host=d.ip or "localhost", port=port)}/health' assert script # set state. first host in placement is master all others backups diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/services/iscsi.py ceph-16.2.6/src/pybind/mgr/cephadm/services/iscsi.py --- ceph-16.2.5/src/pybind/mgr/cephadm/services/iscsi.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/services/iscsi.py 2021-09-16 14:27:19.000000000 +0000 @@ -18,7 +18,7 @@ class IscsiService(CephService): TYPE = 'iscsi' - def config(self, spec: IscsiServiceSpec, daemon_id: str) -> None: # type: ignore + def config(self, spec: IscsiServiceSpec) -> None: # type: ignore assert self.TYPE == spec.service_type assert spec.pool self.mgr._check_pool_exists(spec.pool, spec.service_name()) @@ -150,12 +150,13 @@ """ logger.debug(f'Post remove daemon {self.TYPE}.{daemon.daemon_id}') - # remove config for dashboard iscsi gateways - ret, out, err = self.mgr.check_mon_command({ - 'prefix': 'dashboard iscsi-gateway-rm', - 'name': daemon.hostname, - }) - logger.info(f'{daemon.hostname} removed from iscsi gateways dashboard config') + if 'dashboard' in self.mgr.get('mgr_map')['modules']: + # remove config for dashboard iscsi gateways + ret, out, err = self.mgr.check_mon_command({ + 'prefix': 'dashboard iscsi-gateway-rm', + 'name': daemon.hostname, + }) + logger.info(f'{daemon.hostname} removed from iscsi gateways dashboard config') # needed to know if we have ssl stuff for iscsi in ceph config iscsi_config_dict = {} diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/services/monitoring.py ceph-16.2.6/src/pybind/mgr/cephadm/services/monitoring.py --- ceph-16.2.5/src/pybind/mgr/cephadm/services/monitoring.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/services/monitoring.py 2021-09-16 14:27:19.000000000 +0000 @@ -6,10 +6,10 @@ from mgr_module import HandleCommandResult from orchestrator import DaemonDescription -from ceph.deployment.service_spec import AlertManagerSpec +from ceph.deployment.service_spec import AlertManagerSpec, ServiceSpec from cephadm.services.cephadmservice import CephadmService, CephadmDaemonDeploySpec from cephadm.services.ingress import IngressSpec -from mgr_util import verify_tls, ServerConfigException, create_self_signed_cert +from mgr_util import verify_tls, ServerConfigException, create_self_signed_cert, build_url logger = logging.getLogger(__name__) @@ -49,10 +49,11 @@ cert, pkey = create_self_signed_cert('Ceph', 'cephadm') self.mgr.set_store('grafana_crt', cert) self.mgr.set_store('grafana_key', pkey) - self.mgr.check_mon_command({ - 'prefix': 'dashboard set-grafana-api-ssl-verify', - 'value': 'false', - }) + if 'dashboard' in self.mgr.get('mgr_map')['modules']: + self.mgr.check_mon_command({ + 'prefix': 'dashboard set-grafana-api-ssl-verify', + 'value': 'false', + }) grafana_ini = self.mgr.template.render( 'services/grafana/grafana.ini.j2', { @@ -83,7 +84,7 @@ assert dd.hostname is not None addr = dd.ip if dd.ip else self._inventory_get_addr(dd.hostname) port = dd.ports[0] if dd.ports else self.DEFAULT_SERVICE_PORT - service_url = 'https://{}:{}'.format(addr, port) + service_url = build_url(scheme='https', host=addr, port=port) self._set_service_url_on_dashboard( 'Grafana', 'dashboard get-grafana-api-url', @@ -200,12 +201,29 @@ TYPE = 'prometheus' DEFAULT_SERVICE_PORT = 9095 - def prepare_create(self, daemon_spec: CephadmDaemonDeploySpec) -> CephadmDaemonDeploySpec: + def config(self, spec: ServiceSpec) -> None: + # make sure module is enabled + mgr_map = self.mgr.get('mgr_map') + if 'prometheus' not in mgr_map.get('services', {}): + self.mgr.check_mon_command({ + 'prefix': 'mgr module enable', + 'module': 'prometheus' + }) + # we shouldn't get here (mon will tell the mgr to respawn), but no + # harm done if we do. + + def prepare_create( + self, + daemon_spec: CephadmDaemonDeploySpec, + ) -> CephadmDaemonDeploySpec: assert self.TYPE == daemon_spec.daemon_type daemon_spec.final_config, daemon_spec.deps = self.generate_config(daemon_spec) return daemon_spec - def generate_config(self, daemon_spec: CephadmDaemonDeploySpec) -> Tuple[Dict[str, Any], List[str]]: + def generate_config( + self, + daemon_spec: CephadmDaemonDeploySpec, + ) -> Tuple[Dict[str, Any], List[str]]: assert self.TYPE == daemon_spec.daemon_type deps = [] # type: List[str] diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/services/nfs.py ceph-16.2.6/src/pybind/mgr/cephadm/services/nfs.py --- ceph-16.2.5/src/pybind/mgr/cephadm/services/nfs.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/services/nfs.py 2021-09-16 14:27:19.000000000 +0000 @@ -54,7 +54,7 @@ del rank_map[rank][gen] self.mgr.spec_store.save_rank_map(spec.service_name(), rank_map) - def config(self, spec: NFSServiceSpec, daemon_id: str) -> None: # type: ignore + def config(self, spec: NFSServiceSpec) -> None: # type: ignore from nfs.cluster import create_ganesha_pool assert self.TYPE == spec.service_type diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/templates/services/ingress/keepalived.conf.j2 ceph-16.2.6/src/pybind/mgr/cephadm/templates/services/ingress/keepalived.conf.j2 --- ceph-16.2.5/src/pybind/mgr/cephadm/templates/services/ingress/keepalived.conf.j2 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/templates/services/ingress/keepalived.conf.j2 2021-09-16 14:27:19.000000000 +0000 @@ -19,7 +19,7 @@ } unicast_src_ip {{ host_ip }} unicast_peer { - {% for ip in other_ips %} + {% for ip in other_ips %} {{ ip }} {% endfor %} } diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 ceph-16.2.6/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 --- ceph-16.2.5/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/templates/services/nfs/ganesha.conf.j2 2021-09-16 14:27:19.000000000 +0000 @@ -25,7 +25,7 @@ RADOS_KV { UserId = "{{ user }}"; - nodeid = "{{ nodeid}}"; + nodeid = "{{ nodeid }}"; pool = "{{ pool }}"; namespace = "{{ namespace }}"; } diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/tests/test_cephadm.py ceph-16.2.6/src/pybind/mgr/cephadm/tests/test_cephadm.py --- ceph-16.2.5/src/pybind/mgr/cephadm/tests/test_cephadm.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/tests/test_cephadm.py 2021-09-16 14:27:19.000000000 +0000 @@ -234,15 +234,26 @@ container_id='container_id', version='version', state='running', - ) + ), + dict( + name='something.foo.bar', + style='cephadm', + fsid='fsid', + ), + dict( + name='haproxy.test.bar', + style='cephadm', + fsid='fsid', + ), + ]) )) def test_list_daemons(self, cephadm_module: CephadmOrchestrator): cephadm_module.service_cache_timeout = 10 with with_host(cephadm_module, 'test'): CephadmServe(cephadm_module)._refresh_host_daemons('test') - c = cephadm_module.list_daemons() - assert wait(cephadm_module, c)[0].name() == 'rgw.myrgw.foobar' + dds = wait(cephadm_module, cephadm_module.list_daemons()) + assert {d.name() for d in dds} == {'rgw.myrgw.foobar', 'haproxy.test.bar'} @mock.patch("cephadm.serve.CephadmServe._run_cephadm", _run_cephadm('[]')) def test_daemon_action(self, cephadm_module: CephadmOrchestrator): @@ -1101,7 +1112,7 @@ assert len(cephadm_module.cache.get_daemons_by_type('mgr')) == 3 # put one host in offline state and one host in maintenance state - cephadm_module.inventory._inventory['test2']['status'] = 'offline' + cephadm_module.offline_hosts = {'test2'} cephadm_module.inventory._inventory['test3']['status'] = 'maintenance' cephadm_module.inventory.save() @@ -1109,8 +1120,12 @@ # candidates for scheduling candidates = [ h.hostname for h in cephadm_module._schedulable_hosts()] - assert 'test2' not in candidates - assert 'test3' not in candidates + assert 'test2' in candidates + assert 'test3' in candidates + + unreachable = [h.hostname for h in cephadm_module._unreachable_hosts()] + assert 'test2' in unreachable + assert 'test3' in unreachable with with_service(cephadm_module, ServiceSpec('crash', placement=PlacementSpec(host_pattern='*'))): # re-apply services. No mgr should be removed from maint/offline hosts diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/tests/test_scheduling.py ceph-16.2.6/src/pybind/mgr/cephadm/tests/test_scheduling.py --- ceph-16.2.5/src/pybind/mgr/cephadm/tests/test_scheduling.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/tests/test_scheduling.py 2021-09-16 14:27:19.000000000 +0000 @@ -132,6 +132,7 @@ host_res, to_add, to_remove = HostAssignment( spec=spec, hosts=hosts, + unreachable_hosts=[], daemons=daemons, ).place() if isinstance(host_res, list): @@ -147,6 +148,7 @@ host_res, to_add, to_remove = HostAssignment( spec=spec, hosts=hosts, + unreachable_hosts=[], daemons=daemons ).place() @@ -839,6 +841,7 @@ all_slots, to_add, to_remove = HostAssignment( spec=spec, hosts=[HostSpec(h, labels=['foo']) for h in hosts], + unreachable_hosts=[], daemons=daemons, allow_colo=allow_colo, rank_map=rank_map, @@ -944,6 +947,7 @@ hosts, to_add, to_remove = HostAssignment( spec=ServiceSpec(service_type, placement=placement), hosts=[HostSpec(h, labels=['foo']) for h in hosts], + unreachable_hosts=[], daemons=daemons, ).place() assert len(hosts) == expected_len @@ -977,6 +981,7 @@ hosts, to_add, to_remove = HostAssignment( spec=ServiceSpec(service_type, placement=placement), hosts=[HostSpec(h) for h in hosts], + unreachable_hosts=[], daemons=daemons, ).place() assert len(hosts) == expected_len @@ -1073,6 +1078,7 @@ all_slots, to_add, to_remove = HostAssignment( spec=spec, hosts=[HostSpec(h, labels=['foo']) for h in networks.keys()], + unreachable_hosts=[], daemons=daemons, allow_colo=True, networks=networks, @@ -1158,6 +1164,7 @@ hosts, to_add, to_remove = HostAssignment( spec=ServiceSpec(service_type, placement=placement), hosts=[HostSpec(h) for h in hosts], + unreachable_hosts=[], daemons=daemons, ).place() assert str(e.value) == expected @@ -1333,8 +1340,105 @@ hosts, to_add, to_remove = HostAssignment( spec=spec, hosts=[HostSpec(h) for h in hosts], + unreachable_hosts=[], daemons=daemons, ).place() assert sorted([h.hostname for h in hosts]) in expected assert sorted([h.hostname for h in to_add]) in expected_add assert sorted([h.name() for h in to_remove]) in expected_remove + + +class UnreachableHostsTest(NamedTuple): + service_type: str + placement: PlacementSpec + hosts: List[str] + unreachables_hosts: List[str] + daemons: List[DaemonDescription] + expected_add: List[List[str]] + expected_remove: List[List[str]] + + +@pytest.mark.parametrize("service_type,placement,hosts,unreachable_hosts,daemons,expected_add,expected_remove", + [ + UnreachableHostsTest( + 'mgr', + PlacementSpec(count=3), + 'host1 host2 host3'.split(), + ['host2'], + [], + [['host1', 'host3']], + [[]], + ), + UnreachableHostsTest( + 'mgr', + PlacementSpec(hosts=['host3']), + 'host1 host2 host3'.split(), + ['host1'], + [ + DaemonDescription('mgr', 'a', 'host1'), + DaemonDescription('mgr', 'b', 'host2'), + DaemonDescription('mgr', 'c', 'host3', is_active=True), + ], + [[]], + [['mgr.b']], + ), + UnreachableHostsTest( + 'mgr', + PlacementSpec(count=3), + 'host1 host2 host3 host4'.split(), + ['host1'], + [ + DaemonDescription('mgr', 'a', 'host1'), + DaemonDescription('mgr', 'b', 'host2'), + DaemonDescription('mgr', 'c', 'host3', is_active=True), + ], + [[]], + [[]], + ), + UnreachableHostsTest( + 'mgr', + PlacementSpec(count=1), + 'host1 host2 host3 host4'.split(), + 'host1 host3'.split(), + [ + DaemonDescription('mgr', 'a', 'host1'), + DaemonDescription('mgr', 'b', 'host2'), + DaemonDescription('mgr', 'c', 'host3', is_active=True), + ], + [[]], + [['mgr.b']], + ), + UnreachableHostsTest( + 'mgr', + PlacementSpec(count=3), + 'host1 host2 host3 host4'.split(), + ['host2'], + [], + [['host1', 'host3', 'host4']], + [[]], + ), + UnreachableHostsTest( + 'mgr', + PlacementSpec(count=3), + 'host1 host2 host3 host4'.split(), + 'host1 host4'.split(), + [], + [['host2', 'host3']], + [[]], + ), + + ]) +def test_unreachable_host(service_type, placement, hosts, unreachable_hosts, daemons, expected_add, expected_remove): + + spec = ServiceSpec(service_type=service_type, + service_id=None, + placement=placement) + + hosts, to_add, to_remove = HostAssignment( + spec=spec, + hosts=[HostSpec(h) for h in hosts], + unreachable_hosts=[HostSpec(h) for h in unreachable_hosts], + daemons=daemons, + ).place() + assert sorted([h.hostname for h in to_add]) in expected_add + assert sorted([h.name() for h in to_remove]) in expected_remove diff -Nru ceph-16.2.5/src/pybind/mgr/cephadm/upgrade.py ceph-16.2.6/src/pybind/mgr/cephadm/upgrade.py --- ceph-16.2.5/src/pybind/mgr/cephadm/upgrade.py 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/cephadm/upgrade.py 2021-09-16 14:27:19.000000000 +0000 @@ -138,7 +138,7 @@ completed_types = list(set([completion[0] for completion in completed_daemons if all( c[1] for c in completed_daemons if c[0] == completion[0])])) - return '%s/%s ceph daemons upgraded' % (done, len(daemons)), completed_types + return '%s/%s daemons upgraded' % (done, len(daemons)), completed_types def _check_target_version(self, version: str) -> Optional[str]: try: diff -Nru ceph-16.2.5/src/pybind/mgr/CMakeLists.txt ceph-16.2.6/src/pybind/mgr/CMakeLists.txt --- ceph-16.2.5/src/pybind/mgr/CMakeLists.txt 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/CMakeLists.txt 2021-09-16 14:27:19.000000000 +0000 @@ -6,7 +6,7 @@ endif() if(WITH_TESTS) include(AddCephTest) - add_tox_test(mgr ${CMAKE_CURRENT_SOURCE_DIR} TOX_ENVS py3 mypy flake8) + add_tox_test(mgr ${CMAKE_CURRENT_SOURCE_DIR} TOX_ENVS py3 mypy flake8 jinjalint) endif() # Location needs to match default setting for mgr_module_path, currently: diff -Nru ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/bootstrap-cluster.sh ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/bootstrap-cluster.sh --- ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/bootstrap-cluster.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/bootstrap-cluster.sh 2021-09-16 14:27:19.000000000 +0000 @@ -2,21 +2,23 @@ export PATH=/root/bin:$PATH mkdir /root/bin -{% if ceph_dev_folder is defined %} - cp /mnt/{{ ceph_dev_folder }}/src/cephadm/cephadm /root/bin/cephadm -{% else %} - cd /root/bin - curl --silent --remote-name --location https://raw.githubusercontent.com/ceph/ceph/master/src/cephadm/cephadm -{% endif %} + +cp /mnt/{{ ceph_dev_folder }}/src/cephadm/cephadm /root/bin/cephadm chmod +x /root/bin/cephadm mkdir -p /etc/ceph mon_ip=$(ifconfig eth0 | grep 'inet ' | awk '{ print $2}') -{% if ceph_dev_folder is defined %} - cephadm bootstrap --mon-ip $mon_ip --initial-dashboard-password {{ admin_password }} --allow-fqdn-hostname --dashboard-password-noupdate --shared_ceph_folder /mnt/{{ ceph_dev_folder }} -{% else %} - cephadm bootstrap --mon-ip $mon_ip --initial-dashboard-password {{ admin_password }} --allow-fqdn-hostname --dashboard-password-noupdate -{% endif %} + +cephadm bootstrap --mon-ip $mon_ip --initial-dashboard-password {{ admin_password }} --allow-fqdn-hostname --dashboard-password-noupdate --shared_ceph_folder /mnt/{{ ceph_dev_folder }} + fsid=$(cat /etc/ceph/ceph.conf | grep fsid | awk '{ print $3}') + {% for number in range(1, nodes) %} ssh-copy-id -f -i /etc/ceph/ceph.pub -o StrictHostKeyChecking=no root@{{ prefix }}-node-0{{ number }}.{{ domain }} + {% if expanded_cluster is defined %} + cephadm shell --fsid $fsid -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring ceph orch host add {{ prefix }}-node-0{{ number }}.{{ domain }} + {% endif %} {% endfor %} + +{% if expanded_cluster is defined %} + cephadm shell --fsid $fsid -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring ceph orch apply osd --all-available-devices +{% endif %} diff -Nru ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/ceph_cluster.yml ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/ceph_cluster.yml --- ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/ceph_cluster.yml 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/ceph_cluster.yml 2021-09-16 14:27:19.000000000 +0000 @@ -1,7 +1,7 @@ parameters: nodes: 3 - pool: default - network: default + pool: ceph-dashboard + network: ceph-dashboard domain: cephlab.com prefix: ceph numcpus: 1 @@ -26,15 +26,14 @@ - {{ network }} disks: {{ disks }} pool: {{ pool }} - {% if ceph_dev_folder is defined %} sharedfolders: [{{ ceph_dev_folder }}] - {% endif %} + files: + - bootstrap-cluster.sh cmds: - dnf -y install python3 chrony lvm2 podman - sed -i "s/SELINUX=enforcing/SELINUX=permissive/" /etc/selinux/config - setenforce 0 {% if number == 0 %} - scripts: - - bootstrap-cluster.sh + - bash /root/bootstrap-cluster.sh {% endif %} {% endfor %} diff -Nru ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/run-cephadm-e2e-tests.sh ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/run-cephadm-e2e-tests.sh --- ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/run-cephadm-e2e-tests.sh 2021-07-08 14:03:56.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/run-cephadm-e2e-tests.sh 2021-09-16 14:27:19.000000000 +0000 @@ -2,67 +2,21 @@ set -ex -cleanup() { - if [[ -n "$JENKINS_HOME" ]]; then - printf "\n\nStarting cleanup...\n\n" - kcli delete plan -y ceph || true - sudo podman container prune -f - printf "\n\nCleanup completed.\n\n" - fi -} - -on_error() { - if [ "$1" != "0" ]; then - printf "\n\nERROR $1 thrown on line $2\n\n" - printf "\n\nCollecting info...\n\n" - for vm_id in 0 1 2 - do - local vm="ceph-node-0${vm_id}" - printf "\n\nDisplaying journalctl from VM ${vm}:\n\n" - kcli ssh -u root -- ${vm} 'journalctl --no-tail --no-pager -t cloud-init' || true - printf "\n\nEnd of journalctl from VM ${vm}\n\n" - printf "\n\nDisplaying podman logs:\n\n" - kcli ssh -u root -- ${vm} 'podman logs --names --since 30s $(podman ps -aq)' || true - done - printf "\n\nTEST FAILED.\n\n" - fi -} - -trap 'on_error $? $LINENO' ERR -trap 'cleanup $? $LINENO' EXIT - -sed -i '/ceph-node-/d' $HOME/.ssh/known_hosts - -: ${CEPH_DEV_FOLDER:=${PWD}} - -# Required to start dashboard. -cd ${CEPH_DEV_FOLDER}/src/pybind/mgr/dashboard/frontend -NG_CLI_ANALYTICS=false npm ci -npm run build - -cd ${CEPH_DEV_FOLDER} -kcli delete plan -y ceph || true -kcli create plan -f ./src/pybind/mgr/dashboard/ci/cephadm/ceph_cluster.yml -P ceph_dev_folder=${CEPH_DEV_FOLDER} ceph - -while [[ -z $(kcli ssh -u root -- ceph-node-00 'journalctl --no-tail --no-pager -t cloud-init' | grep "Dashboard is now available") ]]; do - sleep 30 - kcli list vm - # Uncomment for debugging purposes. - #kcli ssh -u root -- ceph-node-00 'podman ps -a' - #kcli ssh -u root -- ceph-node-00 'podman logs --names --since 30s $(podman ps -aq)' - kcli ssh -u root -- ceph-node-00 'journalctl -n 100 --no-pager -t cloud-init' -done - -cd ${CEPH_DEV_FOLDER}/src/pybind/mgr/dashboard/frontend -npx cypress info - : ${CYPRESS_BASE_URL:=''} : ${CYPRESS_LOGIN_USER:='admin'} : ${CYPRESS_LOGIN_PWD:='password'} : ${CYPRESS_ARGS:=''} +: ${DASHBOARD_PORT:='8443'} + +get_vm_ip () { + local ip=$(kcli info vm "$1" -f ip -v | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') + echo -n $ip +} + +if [[ -n "${JENKINS_HOME}" || (-z "${CYPRESS_BASE_URL}" && -z "$(get_vm_ip ceph-node-00)") ]]; then + . "$(dirname $0)"/start-cluster.sh -if [[ -z "${CYPRESS_BASE_URL}" ]]; then - CYPRESS_BASE_URL="https://$(kcli info vm ceph-node-00 -f ip -v | sed -e 's/[^0-9.]//'):8443" + CYPRESS_BASE_URL="https://$(get_vm_ip ceph-node-00):${DASHBOARD_PORT}" fi export CYPRESS_BASE_URL CYPRESS_LOGIN_USER CYPRESS_LOGIN_PWD @@ -71,11 +25,17 @@ local specs="$1" local timeout="$2" local override_config="ignoreTestFiles=*.po.ts,retries=0,testFiles=${specs}" - if [[ -n "$timeout" ]]; then override_config="${override_config},defaultCommandTimeout=${timeout}" fi - npx cypress run ${CYPRESS_ARGS} --browser chrome --headless --config "$override_config" + + rm -f cypress/reports/results-*.xml || true + + npx --no-install cypress run ${CYPRESS_ARGS} --browser chrome --headless --config "$override_config" } +: ${CEPH_DEV_FOLDER:=${PWD}} + +cd ${CEPH_DEV_FOLDER}/src/pybind/mgr/dashboard/frontend + cypress_run "orchestrator/workflow/*-spec.ts" diff -Nru ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/start-cluster.sh ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/start-cluster.sh --- ceph-16.2.5/src/pybind/mgr/dashboard/ci/cephadm/start-cluster.sh 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/dashboard/ci/cephadm/start-cluster.sh 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,86 @@ +#!/usr/bin/env bash + +set -ex + +cleanup() { + set +x + if [[ -n "$JENKINS_HOME" ]]; then + printf "\n\nStarting cleanup...\n\n" + kcli delete plan -y ceph || true + docker container prune -f + printf "\n\nCleanup completed.\n\n" + fi +} + +on_error() { + set +x + if [ "$1" != "0" ]; then + printf "\n\nERROR $1 thrown on line $2\n\n" + printf "\n\nCollecting info...\n\n" + printf "\n\nDisplaying MGR logs:\n\n" + kcli ssh -u root -- ceph-node-00 'cephadm logs -n $(cephadm ls | grep -Eo "mgr\.ceph[0-9a-z.-]+" | head -n 1)' + for vm_id in 0 1 2 + do + local vm="ceph-node-0${vm_id}" + printf "\n\nDisplaying journalctl from VM ${vm}:\n\n" + kcli ssh -u root -- ${vm} 'journalctl --no-tail --no-pager -t cloud-init' || true + printf "\n\nEnd of journalctl from VM ${vm}\n\n" + printf "\n\nDisplaying container logs:\n\n" + kcli ssh -u root -- ${vm} 'podman logs --names --since 30s $(podman ps -aq)' || true + done + printf "\n\nTEST FAILED.\n\n" + fi +} + +trap 'on_error $? $LINENO' ERR +trap 'cleanup $? $LINENO' EXIT + +sed -i '/ceph-node-/d' $HOME/.ssh/known_hosts + +: ${CEPH_DEV_FOLDER:=${PWD}} +EXTRA_PARAMS='' +DEV_MODE='' +# Check script args/options. +for arg in "$@"; do + shift + case "$arg" in + "--dev-mode") DEV_MODE='true'; EXTRA_PARAMS+=" -P dev_mode=${DEV_MODE}" ;; + "--expanded") EXTRA_PARAMS+=" -P expanded_cluster=true" ;; + esac +done + +kcli delete plan -y ceph || true + +# Build dashboard frontend (required to start the module). +cd ${CEPH_DEV_FOLDER}/src/pybind/mgr/dashboard/frontend +export NG_CLI_ANALYTICS=false +if [[ -n "$JENKINS_HOME" ]]; then + npm cache clean --force +fi +npm ci +FRONTEND_BUILD_OPTS='-- --prod' +if [[ -n "${DEV_MODE}" ]]; then + FRONTEND_BUILD_OPTS+=' --deleteOutputPath=false --watch' +fi +npm run build ${FRONTEND_BUILD_OPTS} & + +cd ${CEPH_DEV_FOLDER} +: ${VM_IMAGE:='fedora34'} +: ${VM_IMAGE_URL:='https://fedora.mirror.liteserver.nl/linux/releases/34/Cloud/x86_64/images/Fedora-Cloud-Base-34-1.2.x86_64.qcow2'} +kcli download image -p ceph-dashboard -u ${VM_IMAGE_URL} ${VM_IMAGE} +kcli delete plan -y ceph || true +kcli create plan -f ./src/pybind/mgr/dashboard/ci/cephadm/ceph_cluster.yml \ + -P ceph_dev_folder=${CEPH_DEV_FOLDER} \ + ${EXTRA_PARAMS} ceph + +: ${CLUSTER_DEBUG:=0} +: ${DASHBOARD_CHECK_INTERVAL:=10} +while [[ -z $(kcli ssh -u root -- ceph-node-00 'journalctl --no-tail --no-pager -t cloud-init' | grep "Dashboard is now available") ]]; do + sleep ${DASHBOARD_CHECK_INTERVAL} + kcli list vm + if [[ ${CLUSTER_DEBUG} != 0 ]]; then + kcli ssh -u root -- ceph-node-00 'podman ps -a' + kcli ssh -u root -- ceph-node-00 'podman logs --names --since 30s $(podman ps -aq)' + fi + kcli ssh -u root -- ceph-node-00 'journalctl -n 100 --no-pager -t cloud-init' +done diff -Nru ceph-16.2.5/src/pybind/mgr/dashboard/ci/check_grafana_dashboards.py ceph-16.2.6/src/pybind/mgr/dashboard/ci/check_grafana_dashboards.py --- ceph-16.2.5/src/pybind/mgr/dashboard/ci/check_grafana_dashboards.py 1970-01-01 00:00:00.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/dashboard/ci/check_grafana_dashboards.py 2021-09-16 14:27:19.000000000 +0000 @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +# pylint: disable=F0401 +""" +This script does: +* Scan through Angular html templates and extract tags +* Check if every tag has a corresponding Grafana dashboard by `uid` + +Usage: + python + diff -Nru ceph-16.2.5/src/pybind/mgr/dashboard/frontend/dist/en-US/main.686c64fd8301e15fd70a.js ceph-16.2.6/src/pybind/mgr/dashboard/frontend/dist/en-US/main.686c64fd8301e15fd70a.js --- ceph-16.2.5/src/pybind/mgr/dashboard/frontend/dist/en-US/main.686c64fd8301e15fd70a.js 2021-07-08 14:10:20.000000000 +0000 +++ ceph-16.2.6/src/pybind/mgr/dashboard/frontend/dist/en-US/main.686c64fd8301e15fd70a.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -var $localize=Object.assign(void 0===$localize?{}:$localize,{locale:"en-US"}); -"use strict";(function(global){global.ng=global.ng||{};global.ng.common=global.ng.common||{};global.ng.common.locales=global.ng.common.locales||{};const u=undefined;function plural(n){let i=Math.floor(Math.abs(n)),v=n.toString().replace(/^[^.]*\.?/,"").length;if(i===1&&v===0)return 1;return 5}global.ng.common.locales["en-us-posix"]=["en-US-POSIX",[["a","p"],["AM","PM"],u],[["AM","PM"],u,u],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],u,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],u,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",u,"{1} 'at' {0}",u],[".",",",";","%","+","-","E","\xD7","0/00","INF","NaN",":"],["0.######","0%","\xA4\xA00.00","0.000000E+000"],"USD","$","US Dollar",{},"ltr",plural,[[["mi","n","in the morning","in the afternoon","in the evening","at night"],["midnight","noon","in the morning","in the afternoon","in the evening","at night"],u],[["midnight","noon","morning","afternoon","evening","night"],u,u],["00:00","12:00",["06:00","12:00"],["12:00","18:00"],["18:00","21:00"],["21:00","06:00"]]]]})(typeof globalThis!=="undefined"&&globalThis||typeof global!=="undefined"&&global||typeof window!=="undefined"&&window);; -(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{"+0ag":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){const t=/ceph version\s+[^ ]+\s+\(.+\)\s+(.+)\s+\((.+)\)/.exec(e);return t?"dev"===t[2]?"master":t[1]:e}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"cephReleaseName",type:e,pure:!0}),e})()},"+EKe":function(e,t,n){"use strict";var i=n("23KU"),r=n("uE2L");t.a=function(e,t,n,s){var o=!n;n||(n={});for(var a=-1,c=t.length;++a=20?"ste":"de")},week:{dow:1,doy:4}})}(n("wd/R"))},"//9w":function(e,t,n){!function(e){"use strict";e.defineLocale("se",{months:"o\u0111\u0111ajagem\xe1nnu_guovvam\xe1nnu_njuk\u010dam\xe1nnu_cuo\u014bom\xe1nnu_miessem\xe1nnu_geassem\xe1nnu_suoidnem\xe1nnu_borgem\xe1nnu_\u010dak\u010dam\xe1nnu_golggotm\xe1nnu_sk\xe1bmam\xe1nnu_juovlam\xe1nnu".split("_"),monthsShort:"o\u0111\u0111j_guov_njuk_cuo_mies_geas_suoi_borg_\u010dak\u010d_golg_sk\xe1b_juov".split("_"),weekdays:"sotnabeaivi_vuoss\xe1rga_ma\u014b\u014beb\xe1rga_gaskavahkku_duorastat_bearjadat_l\xe1vvardat".split("_"),weekdaysShort:"sotn_vuos_ma\u014b_gask_duor_bear_l\xe1v".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s gea\u017ees",past:"ma\u014bit %s",s:"moadde sekunddat",ss:"%d sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta m\xe1nnu",MM:"%d m\xe1nut",y:"okta jahki",yy:"%d jagit"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},"/1FC":function(e,t,n){"use strict";t.a=Array.isArray},"/GqU":function(e,t,n){var i=n("RK3t"),r=n("HYAF");e.exports=function(e){return i(r(e))}},"/NlG":function(e,t,n){"use strict";n.d(t,"a",(function(){return _}));var i=n("oxzT"),r=n("8Y7J"),s=n("G0yt"),o=n("SVse");const a=function(e){return[e]};function c(e,t){if(1&e&&(r.Sb(0,"td",8),r.Nb(1,"i",9),r.Rb()),2&e){const e=r.ic(2);r.yb(1),r.Cb("alert-",e.bootstrapClass," ",e.typeIcon,""),r.pc("ngClass",r.uc(5,a,e.icons.large3x))}}function l(e,t){if(1&e&&(r.Sb(0,"td",10),r.Oc(1),r.Rb()),2&e){const e=r.ic(2);r.yb(1),r.Pc(e.title)}}function u(e,t){1&e&&r.Ob(0)}function d(e,t){if(1&e&&(r.Qb(0),r.Sb(1,"tr"),r.Mc(2,c,2,7,"td",4),r.Mc(3,l,2,1,"td",5),r.Rb(),r.Sb(4,"tr"),r.Sb(5,"td",6),r.Mc(6,u,1,0,"ng-container",7),r.Rb(),r.Rb(),r.Pb()),2&e){const e=r.ic(),t=r.Ac(6);r.yb(2),r.pc("ngIf",e.showIcon),r.yb(1),r.pc("ngIf",e.showTitle),r.yb(3),r.pc("ngTemplateOutlet",t)}}function h(e,t){if(1&e&&(r.Sb(0,"td",12),r.Nb(1,"i",13),r.Rb()),2&e){const e=r.ic(2);r.yb(1),r.Cb("alert-",e.bootstrapClass," ",e.typeIcon,"")}}function f(e,t){if(1&e&&(r.Sb(0,"td",10),r.Oc(1),r.Rb()),2&e){const e=r.ic(2);r.yb(1),r.Pc(e.title)}}function p(e,t){1&e&&r.Ob(0)}function m(e,t){if(1&e&&(r.Sb(0,"tr"),r.Mc(1,h,2,4,"td",11),r.Mc(2,f,2,1,"td",5),r.Sb(3,"td",6),r.Mc(4,p,1,0,"ng-container",7),r.Rb(),r.Rb()),2&e){const e=r.ic(),t=r.Ac(6);r.yb(1),r.pc("ngIf",e.showIcon),r.yb(1),r.pc("ngIf",e.showTitle),r.yb(2),r.pc("ngTemplateOutlet",t)}}function b(e,t){1&e&&r.nc(0)}const g=["*"];let _=(()=>{class e{constructor(){this.title="",this.bootstrapClass="",this.size="normal",this.showIcon=!0,this.showTitle=!0,this.icons=i.a}ngOnInit(){switch(this.type){case"warning":this.title=this.title||"Warning",this.typeIcon=this.typeIcon||i.a.warning,this.bootstrapClass=this.bootstrapClass||"warning";break;case"error":this.title=this.title||"Error",this.typeIcon=this.typeIcon||i.a.destroyCircle,this.bootstrapClass=this.bootstrapClass||"danger";break;case"info":this.title=this.title||"Information",this.typeIcon=this.typeIcon||i.a.infoCircle,this.bootstrapClass=this.bootstrapClass||"info";break;case"success":this.title=this.title||"Success",this.typeIcon=this.typeIcon||i.a.check,this.bootstrapClass=this.bootstrapClass||"success"}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=r.Gb({type:e,selectors:[["cd-alert-panel"]],inputs:{title:"title",bootstrapClass:"bootstrapClass",type:"type",typeIcon:"typeIcon",size:"size",showIcon:"showIcon",showTitle:"showTitle"},ngContentSelectors:g,decls:7,vars:4,consts:[[3,"type","dismissible"],[4,"ngIf","ngIfElse"],["slim",""],["content",""],["rowspan","2","class","alert-panel-icon",4,"ngIf"],["class","alert-panel-title",4,"ngIf"],[1,"alert-panel-text"],[4,"ngTemplateOutlet"],["rowspan","2",1,"alert-panel-icon"],["aria-hidden","true",3,"ngClass"],[1,"alert-panel-title"],["class","alert-panel-icon",4,"ngIf"],[1,"alert-panel-icon"],["aria-hidden","true"]],template:function(e,t){if(1&e&&(r.oc(),r.Sb(0,"ngb-alert",0),r.Sb(1,"table"),r.Mc(2,d,7,3,"ng-container",1),r.Mc(3,m,5,3,"ng-template",null,2,r.Nc),r.Rb(),r.Rb(),r.Mc(5,b,1,0,"ng-template",null,3,r.Nc)),2&e){const e=r.Ac(4);r.qc("type",t.bootstrapClass),r.pc("dismissible",!1),r.yb(2),r.pc("ngIf","normal"===t.size)("ngIfElse",e)}},directives:[s.b,o.r,o.w,o.p],styles:[".alert-panel-icon[_ngcontent-%COMP%]{padding-right:.5em;vertical-align:top}.alert-panel-title[_ngcontent-%COMP%]{font-weight:700}"]}),e})()},"/X5v":function(e,t,n){!function(e){"use strict";e.defineLocale("x-pseudo",{months:"J~\xe1\xf1\xfa\xe1~r\xfd_F~\xe9br\xfa~\xe1r\xfd_~M\xe1rc~h_\xc1p~r\xedl_~M\xe1\xfd_~J\xfa\xf1\xe9~_J\xfal~\xfd_\xc1\xfa~g\xfast~_S\xe9p~t\xe9mb~\xe9r_\xd3~ct\xf3b~\xe9r_\xd1~\xf3v\xe9m~b\xe9r_~D\xe9c\xe9~mb\xe9r".split("_"),monthsShort:"J~\xe1\xf1_~F\xe9b_~M\xe1r_~\xc1pr_~M\xe1\xfd_~J\xfa\xf1_~J\xfal_~\xc1\xfag_~S\xe9p_~\xd3ct_~\xd1\xf3v_~D\xe9c".split("_"),monthsParseExact:!0,weekdays:"S~\xfa\xf1d\xe1~\xfd_M\xf3~\xf1d\xe1\xfd~_T\xfa\xe9~sd\xe1\xfd~_W\xe9d~\xf1\xe9sd~\xe1\xfd_T~h\xfars~d\xe1\xfd_~Fr\xedd~\xe1\xfd_S~\xe1t\xfar~d\xe1\xfd".split("_"),weekdaysShort:"S~\xfa\xf1_~M\xf3\xf1_~T\xfa\xe9_~W\xe9d_~Th\xfa_~Fr\xed_~S\xe1t".split("_"),weekdaysMin:"S~\xfa_M\xf3~_T\xfa_~W\xe9_T~h_Fr~_S\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~\xf3d\xe1~\xfd \xe1t] LT",nextDay:"[T~\xf3m\xf3~rr\xf3~w \xe1t] LT",nextWeek:"dddd [\xe1t] LT",lastDay:"[\xdd~\xe9st~\xe9rd\xe1~\xfd \xe1t] LT",lastWeek:"[L~\xe1st] dddd [\xe1t] LT",sameElse:"L"},relativeTime:{future:"\xed~\xf1 %s",past:"%s \xe1~g\xf3",s:"\xe1 ~f\xe9w ~s\xe9c\xf3~\xf1ds",ss:"%d s~\xe9c\xf3\xf1~ds",m:"\xe1 ~m\xed\xf1~\xfat\xe9",mm:"%d m~\xed\xf1\xfa~t\xe9s",h:"\xe1~\xf1 h\xf3~\xfar",hh:"%d h~\xf3\xfars",d:"\xe1 ~d\xe1\xfd",dd:"%d d~\xe1\xfds",M:"\xe1 ~m\xf3\xf1~th",MM:"%d m~\xf3\xf1t~hs",y:"\xe1 ~\xfd\xe9\xe1r",yy:"%d \xfd~\xe9\xe1rs"},dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(n("wd/R"))},"/b8u":function(e,t,n){var i=n("STAE");e.exports=i&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},"/byt":function(e,t){e.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},"/uUt":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("7o/Q");function r(e,t){return n=>n.lift(new s(e,t))}class s{constructor(e,t){this.compare=e,this.keySelector=t}call(e,t){return t.subscribe(new o(e,this.compare,this.keySelector))}}class o extends i.a{constructor(e,t,n){super(e),this.keySelector=n,this.hasKey=!1,"function"==typeof t&&(this.compare=t)}compare(e,t){return e===t}_next(e){let t;try{const{keySelector:n}=this;t=n?n(e):e}catch(i){return this.destination.error(i)}let n=!1;if(this.hasKey)try{const{compare:e}=this;n=e(this.key,t)}catch(i){return this.destination.error(i)}else this.hasKey=!0;n||(this.key=t,this.destination.next(e))}}},0:function(e,t,n){e.exports=n("zUnb")},"0+/T":function(e,t,n){"use strict";n.d(t,"a",(function(){return D}));var i=n("s7LF"),r=n("QFaf"),s=n("sb0X"),o=n("8Y7J"),a=n("G0yt"),c=n("ajRT"),l=n("SVse"),u=n("NwgZ"),d=n("ocLN"),h=n("ANnk"),f=n("f69J"),p=n("IZUe"),m=n("6+kj");function b(e,t){1&e&&o.Ob(0)}function g(e,t){1&e&&o.Ob(0)}function _(e,t){if(1&e&&(o.Sb(0,"p"),o.cc(1,21),o.jc(2,"lowercase"),o.Nb(3,"strong"),o.Zb(),o.Rb()),2&e){const e=o.ic(2);o.yb(3),o.ac(o.kc(2,2,e.actionDescription))(e.itemNames[0]),o.Xb(1)}}function y(e,t){if(1&e&&(o.Sb(0,"li"),o.Sb(1,"strong"),o.Oc(2),o.Rb(),o.Rb()),2&e){const e=t.$implicit;o.yb(2),o.Pc(e)}}function v(e,t){if(1&e&&(o.Sb(0,"p"),o.Wb(1,22),o.jc(2,"lowercase"),o.Rb(),o.Sb(3,"ul"),o.Mc(4,y,3,1,"li",23),o.Rb()),2&e){const e=o.ic(2);o.yb(2),o.ac(o.kc(2,2,e.actionDescription)),o.Xb(1),o.yb(2),o.pc("ngForOf",e.itemNames)}}function w(e,t){if(1&e&&(o.Sb(0,"span"),o.Mc(1,_,4,4,"p",10),o.Mc(2,v,5,4,"ng-template",null,20,o.Nc),o.Rb()),2&e){const e=o.Ac(3),t=o.ic();o.yb(1),o.pc("ngIf",1===t.itemNames.length)("ngIfElse",e)}}function S(e,t){if(1&e&&(o.Sb(0,"p"),o.Wb(1,24),o.jc(2,"lowercase"),o.Rb()),2&e){const e=o.ic();o.yb(2),o.ac(o.kc(2,2,e.actionDescription))(e.itemDescription),o.Xb(1)}}function M(e,t){1&e&&o.Ob(0)}function x(e,t){if(1&e&&(o.Oc(0),o.jc(1,"titlecase")),2&e){const e=o.ic();o.Rc(" ",o.kc(1,2,e.actionDescription)," ",e.itemDescription,"\n")}}const k=function(e){return{form:e}};let D=(()=>{class e{constructor(e){this.activeModal=e,this.actionDescription="delete"}ngOnInit(){const e={confirmation:new i.h(!1,[i.A.requiredTrue])};if(this.childFormGroup&&(e.child=this.childFormGroup),this.deletionForm=new r.a(e),!this.submitAction&&!this.submitActionObservable)throw new Error("No submit action defined")}callSubmitAction(){this.submitActionObservable?this.submitActionObservable().subscribe({error:this.stopLoadingSpinner.bind(this),complete:this.hideModal.bind(this)}):this.submitAction()}hideModal(){this.activeModal.close()}stopLoadingSpinner(){this.deletionForm.setErrors({cdSubmitButton:!0})}}return e.\u0275fac=function(t){return new(t||e)(o.Mb(a.a))},e.\u0275cmp=o.Gb({type:e,selectors:[["cd-deletion-modal"]],viewQuery:function(e,t){var n;1&e&&o.Jc(s.a,!0),2&e&&o.zc(n=o.hc())&&(t.submitButton=n.first)},decls:24,vars:15,consts:function(){return[[3,"modalRef"],["modal",""],[1,"modal-title"],[4,"ngTemplateOutlet"],[1,"modal-content"],["name","deletionForm","novalidate","",3,"formGroup"],["formDir","ngForm"],[1,"modal-body"],[4,"ngTemplateOutlet","ngTemplateOutletContext"],[1,"question"],[4,"ngIf","ngIfElse"],["noNames",""],[1,"form-group"],[1,"custom-control","custom-checkbox"],["type","checkbox","name","confirmation","id","confirmation","formControlName","confirmation","autofocus","",1,"custom-control-input"],["for","confirmation",1,"custom-control-label"],"Yes, I am sure.",[1,"modal-footer"],[3,"form","submitText","submitActionEvent"],["deletionHeading",""],["manyNames",""],"Are you sure that you want to " + "\ufffd0\ufffd" + " " + "\ufffd#3\ufffd" + "" + "\ufffd1\ufffd" + "" + "\ufffd/#3\ufffd" + "?","Are you sure that you want to " + "\ufffd0\ufffd" + " the selected items?",[4,"ngFor","ngForOf"],"Are you sure that you want to " + "\ufffd0\ufffd" + " the selected " + "\ufffd1\ufffd" + "?"]},template:function(e,t){if(1&e&&(o.Sb(0,"cd-modal",0,1),o.Qb(2,2),o.Mc(3,b,1,0,"ng-container",3),o.Pb(),o.Qb(4,4),o.Sb(5,"form",5,6),o.Sb(7,"div",7),o.Mc(8,g,1,0,"ng-container",8),o.Sb(9,"div",9),o.Mc(10,w,4,2,"span",10),o.Mc(11,S,3,4,"ng-template",null,11,o.Nc),o.Mc(13,M,1,0,"ng-container",8),o.Sb(14,"div",12),o.Sb(15,"div",13),o.Nb(16,"input",14),o.Sb(17,"label",15),o.Wb(18,16),o.Rb(),o.Rb(),o.Rb(),o.Rb(),o.Rb(),o.Sb(19,"div",17),o.Sb(20,"cd-form-button-panel",18),o.gc("submitActionEvent",(function(){return t.callSubmitAction()})),o.jc(21,"titlecase"),o.Rb(),o.Rb(),o.Rb(),o.Pb(),o.Rb(),o.Mc(22,x,2,4,"ng-template",null,19,o.Nc)),2&e){const e=o.Ac(12),n=o.Ac(23);o.pc("modalRef",t.activeModal),o.yb(3),o.pc("ngTemplateOutlet",n),o.yb(2),o.pc("formGroup",t.deletionForm),o.yb(3),o.pc("ngTemplateOutlet",t.bodyTemplate)("ngTemplateOutletContext",t.bodyContext),o.yb(2),o.pc("ngIf",t.itemNames)("ngIfElse",e),o.yb(3),o.pc("ngTemplateOutlet",t.childFormGroupTemplate)("ngTemplateOutletContext",o.uc(13,k,t.deletionForm)),o.yb(7),o.pc("form",t.deletionForm)("submitText",o.kc(21,11,t.actionDescription)+" "+t.itemDescription)}},directives:[c.a,l.w,i.C,i.r,i.k,u.a,l.r,d.a,h.a,i.b,f.a,i.q,i.i,p.a,m.a,l.q],pipes:[l.A,l.o],styles:[".modal-body[_ngcontent-%COMP%] .question[_ngcontent-%COMP%]{margin-top:1em}.modal-body[_ngcontent-%COMP%] label[_ngcontent-%COMP%]{font-weight:700}.modal-body[_ngcontent-%COMP%] .question[_ngcontent-%COMP%] .form-check[_ngcontent-%COMP%]{padding-top:7px}"]}),e})()},"07d7":function(e,t,n){var i=n("AO7/"),r=n("busE"),s=n("sEFX");i||r(Object.prototype,"toString",s,{unsafe:!0})},"0BK2":function(e,t){e.exports={}},"0Dky":function(e,t){e.exports=function(e){try{return!!e()}catch(t){return!0}}},"0EUg":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("bHdf");function r(){return Object(i.a)(1)}},"0GbY":function(e,t,n){var i=n("Qo9l"),r=n("2oRo"),s=function(e){return"function"==typeof e?e:void 0};e.exports=function(e,t){return arguments.length<2?s(i[e])||s(r[e]):i[e]&&i[e][t]||r[e]&&r[e][t]}},"0eef":function(e,t,n){"use strict";var i={}.propertyIsEnumerable,r=Object.getOwnPropertyDescriptor,s=r&&!i.call({1:2},1);t.f=s?function(e){var t=r(this,e);return!!t&&t.enumerable}:i},"0mo+":function(e,t,n){!function(e){"use strict";var t={1:"\u0f21",2:"\u0f22",3:"\u0f23",4:"\u0f24",5:"\u0f25",6:"\u0f26",7:"\u0f27",8:"\u0f28",9:"\u0f29",0:"\u0f20"},n={"\u0f21":"1","\u0f22":"2","\u0f23":"3","\u0f24":"4","\u0f25":"5","\u0f26":"6","\u0f27":"7","\u0f28":"8","\u0f29":"9","\u0f20":"0"};e.defineLocale("bo",{months:"\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f51\u0f44\u0f0b\u0f54\u0f7c_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f42\u0f49\u0f72\u0f66\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f42\u0f66\u0f74\u0f58\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f5e\u0f72\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f63\u0f94\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f51\u0fb2\u0f74\u0f42\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f51\u0f74\u0f53\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f62\u0f92\u0fb1\u0f51\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f51\u0f42\u0f74\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f45\u0f74\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f45\u0f74\u0f0b\u0f42\u0f45\u0f72\u0f42\u0f0b\u0f54_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f56\u0f45\u0f74\u0f0b\u0f42\u0f49\u0f72\u0f66\u0f0b\u0f54".split("_"),monthsShort:"\u0f5f\u0fb3\u0f0b1_\u0f5f\u0fb3\u0f0b2_\u0f5f\u0fb3\u0f0b3_\u0f5f\u0fb3\u0f0b4_\u0f5f\u0fb3\u0f0b5_\u0f5f\u0fb3\u0f0b6_\u0f5f\u0fb3\u0f0b7_\u0f5f\u0fb3\u0f0b8_\u0f5f\u0fb3\u0f0b9_\u0f5f\u0fb3\u0f0b10_\u0f5f\u0fb3\u0f0b11_\u0f5f\u0fb3\u0f0b12".split("_"),monthsShortRegex:/^(\u0f5f\u0fb3\u0f0b\d{1,2})/,monthsParseExact:!0,weekdays:"\u0f42\u0f5f\u0f60\u0f0b\u0f49\u0f72\u0f0b\u0f58\u0f0b_\u0f42\u0f5f\u0f60\u0f0b\u0f5f\u0fb3\u0f0b\u0f56\u0f0b_\u0f42\u0f5f\u0f60\u0f0b\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b_\u0f42\u0f5f\u0f60\u0f0b\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b_\u0f42\u0f5f\u0f60\u0f0b\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74_\u0f42\u0f5f\u0f60\u0f0b\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b_\u0f42\u0f5f\u0f60\u0f0b\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b".split("_"),weekdaysShort:"\u0f49\u0f72\u0f0b\u0f58\u0f0b_\u0f5f\u0fb3\u0f0b\u0f56\u0f0b_\u0f58\u0f72\u0f42\u0f0b\u0f51\u0f58\u0f62\u0f0b_\u0f63\u0fb7\u0f42\u0f0b\u0f54\u0f0b_\u0f55\u0f74\u0f62\u0f0b\u0f56\u0f74_\u0f54\u0f0b\u0f66\u0f44\u0f66\u0f0b_\u0f66\u0fa4\u0f7a\u0f53\u0f0b\u0f54\u0f0b".split("_"),weekdaysMin:"\u0f49\u0f72_\u0f5f\u0fb3_\u0f58\u0f72\u0f42_\u0f63\u0fb7\u0f42_\u0f55\u0f74\u0f62_\u0f66\u0f44\u0f66_\u0f66\u0fa4\u0f7a\u0f53".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[\u0f51\u0f72\u0f0b\u0f62\u0f72\u0f44] LT",nextDay:"[\u0f66\u0f44\u0f0b\u0f49\u0f72\u0f53] LT",nextWeek:"[\u0f56\u0f51\u0f74\u0f53\u0f0b\u0f55\u0fb2\u0f42\u0f0b\u0f62\u0f97\u0f7a\u0f66\u0f0b\u0f58], LT",lastDay:"[\u0f41\u0f0b\u0f66\u0f44] LT",lastWeek:"[\u0f56\u0f51\u0f74\u0f53\u0f0b\u0f55\u0fb2\u0f42\u0f0b\u0f58\u0f50\u0f60\u0f0b\u0f58] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0f63\u0f0b",past:"%s \u0f66\u0f94\u0f53\u0f0b\u0f63",s:"\u0f63\u0f58\u0f0b\u0f66\u0f44",ss:"%d \u0f66\u0f90\u0f62\u0f0b\u0f46\u0f0d",m:"\u0f66\u0f90\u0f62\u0f0b\u0f58\u0f0b\u0f42\u0f45\u0f72\u0f42",mm:"%d \u0f66\u0f90\u0f62\u0f0b\u0f58",h:"\u0f46\u0f74\u0f0b\u0f5a\u0f7c\u0f51\u0f0b\u0f42\u0f45\u0f72\u0f42",hh:"%d \u0f46\u0f74\u0f0b\u0f5a\u0f7c\u0f51",d:"\u0f49\u0f72\u0f53\u0f0b\u0f42\u0f45\u0f72\u0f42",dd:"%d \u0f49\u0f72\u0f53\u0f0b",M:"\u0f5f\u0fb3\u0f0b\u0f56\u0f0b\u0f42\u0f45\u0f72\u0f42",MM:"%d \u0f5f\u0fb3\u0f0b\u0f56",y:"\u0f63\u0f7c\u0f0b\u0f42\u0f45\u0f72\u0f42",yy:"%d \u0f63\u0f7c"},preparse:function(e){return e.replace(/[\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\u0f29\u0f20]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0f58\u0f5a\u0f53\u0f0b\u0f58\u0f7c|\u0f5e\u0f7c\u0f42\u0f66\u0f0b\u0f40\u0f66|\u0f49\u0f72\u0f53\u0f0b\u0f42\u0f74\u0f44|\u0f51\u0f42\u0f7c\u0f44\u0f0b\u0f51\u0f42|\u0f58\u0f5a\u0f53\u0f0b\u0f58\u0f7c/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0f58\u0f5a\u0f53\u0f0b\u0f58\u0f7c"===t&&e>=4||"\u0f49\u0f72\u0f53\u0f0b\u0f42\u0f74\u0f44"===t&&e<5||"\u0f51\u0f42\u0f7c\u0f44\u0f0b\u0f51\u0f42"===t?e+12:e},meridiem:function(e,t,n){return e<4?"\u0f58\u0f5a\u0f53\u0f0b\u0f58\u0f7c":e<10?"\u0f5e\u0f7c\u0f42\u0f66\u0f0b\u0f40\u0f66":e<17?"\u0f49\u0f72\u0f53\u0f0b\u0f42\u0f74\u0f44":e<20?"\u0f51\u0f42\u0f7c\u0f44\u0f0b\u0f51\u0f42":"\u0f58\u0f5a\u0f53\u0f0b\u0f58\u0f7c"},week:{dow:0,doy:6}})}(n("wd/R"))},"0rvr":function(e,t,n){var i=n("glrk"),r=n("O741");e.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var e,t=!1,n={};try{(e=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(n,[]),t=n instanceof Array}catch(s){}return function(n,s){return i(n),r(s),t?e.call(n,s):n.__proto__=s,n}}():void 0)},"0tRk":function(e,t,n){!function(e){"use strict";e.defineLocale("pt-br",{months:"janeiro_fevereiro_mar\xe7o_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"domingo_segunda-feira_ter\xe7a-feira_quarta-feira_quinta-feira_sexta-feira_s\xe1bado".split("_"),weekdaysShort:"dom_seg_ter_qua_qui_sex_s\xe1b".split("_"),weekdaysMin:"do_2\xaa_3\xaa_4\xaa_5\xaa_6\xaa_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [\xe0s] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [\xe0s] HH:mm"},calendar:{sameDay:"[Hoje \xe0s] LT",nextDay:"[Amanh\xe3 \xe0s] LT",nextWeek:"dddd [\xe0s] LT",lastDay:"[Ontem \xe0s] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[\xdaltimo] dddd [\xe0s] LT":"[\xdaltima] dddd [\xe0s] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"h\xe1 %s",s:"poucos segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um m\xeas",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",invalidDate:"Data inv\xe1lida"})}(n("wd/R"))},"14Sl":function(e,t,n){"use strict";n("rB9j");var i=n("busE"),r=n("kmMV"),s=n("0Dky"),o=n("tiKp"),a=n("kRJp"),c=o("species"),l=RegExp.prototype,u=!s((function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")})),d="$0"==="a".replace(/./,"$0"),h=o("replace"),f=!!/./[h]&&""===/./[h]("a","$0"),p=!s((function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var n="ab".split(e);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));e.exports=function(e,t,n,h){var m=o(e),b=!s((function(){var t={};return t[m]=function(){return 7},7!=""[e](t)})),g=b&&!s((function(){var t=!1,n=/a/;return"split"===e&&((n={}).constructor={},n.constructor[c]=function(){return n},n.flags="",n[m]=/./[m]),n.exec=function(){return t=!0,null},n[m](""),!t}));if(!b||!g||"replace"===e&&(!u||!d||f)||"split"===e&&!p){var _=/./[m],y=n(m,""[e],(function(e,t,n,i,s){var o=t.exec;return o===r||o===l.exec?b&&!s?{done:!0,value:_.call(t,n,i)}:{done:!0,value:e.call(n,t,i)}:{done:!1}}),{REPLACE_KEEPS_$0:d,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:f}),v=y[1];i(String.prototype,e,y[0]),i(l,m,2==t?function(e,t){return v.call(e,this,t)}:function(e){return v.call(e,this)})}h&&a(l[m],"sham",!0)}},"1E5z":function(e,t,n){var i=n("m/L8").f,r=n("UTVS"),s=n("tiKp")("toStringTag");e.exports=function(e,t,n){e&&!r(e=n?e:e.prototype,s)&&i(e,s,{configurable:!0,value:t})}},"1G5W":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("zx2A");function r(e){return t=>t.lift(new s(e))}class s{constructor(e){this.notifier=e}call(e,t){const n=new o(e),r=Object(i.c)(this.notifier,new i.a(n));return r&&!n.seenValue?(n.add(r),t.subscribe(n)):n}}class o extends i.b{constructor(e){super(e),this.seenValue=!1}notifyNext(){this.seenValue=!0,this.complete()}notifyComplete(){}}},"1Ni5":function(e,t,n){"use strict";n.d(t,"b",(function(){return f})),n.d(t,"a",(function(){return p}));var i=n("s7LF"),r=n("LvDl"),s=n.n(r),o=n("LRne"),a=n("PqYM"),c=n("aGrj"),l=n("lJxs"),u=n("IzEk"),d=n("Fgil"),h=n("aXbf");function f(e){return null==e||0===e.length}class p{static email(e){return f(e.value)?null:i.A.email(e)}static ip(e=0){const t=/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i,n=/^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}$/i;return i.A.pattern(4===e?t:6===e?n:new RegExp(t.source+"|"+n.source))}static number(e=!0){return i.A.pattern(e?/^-?[0-9]+$/i:/^[0-9]+$/i)}static decimalNumber(e=!0){return i.A.pattern(e?/^-?[0-9]+(.[0-9]+)?$/i:/^[0-9]+(.[0-9]+)?$/i)}static sslCert(){return i.A.pattern(/^-----BEGIN CERTIFICATE-----(\n|\r|\f)((.+)?((\n|\r|\f).+)*)(\n|\r|\f)-----END CERTIFICATE-----[\n\r\f]*$/)}static sslPrivKey(){return i.A.pattern(/^-----BEGIN RSA PRIVATE KEY-----(\n|\r|\f)((.+)?((\n|\r|\f).+)*)(\n|\r|\f)-----END RSA PRIVATE KEY-----[\n\r\f]*$/)}static requiredIf(e,t){let n=!1;return i=>(!n&&i.parent&&(Object.keys(e).forEach(e=>{i.parent.get(e).valueChanges.subscribe(()=>{i.updateValueAndValidity({emitEvent:!1})})}),n=!0),Object.keys(e).every(t=>{if(!i.parent)return!1;const n=i.parent.get(t).value,r=e[t];if(s.a.isObjectLike(r)){let e=!1;switch(r.op){case"empty":e=s.a.isEmpty(n);break;case"!empty":e=!s.a.isEmpty(n);break;case"equal":e=n===r.arg1;break;case"!equal":e=n!==r.arg1;break;case"minLength":s.a.isString(n)&&(e=n.length>=r.arg1)}return e}return n===r})&&(s.a.isFunction(t)?t.call(t,i.value):f(i.value))?{required:!0}:null)}static composeIf(e,t){let n=!1;return r=>(!n&&r.parent&&(Object.keys(e).forEach(e=>{r.parent.get(e).valueChanges.subscribe(()=>{r.updateValueAndValidity({emitEvent:!1})})}),n=!0),Object.keys(e).every(t=>r.parent&&r.parent.get(t).value===e[t])?i.A.compose(t)(r):null)}static custom(e,t){return n=>{const i=t.call(this,n.value);return i?{[e]:i}:null}}static validateIf(e,t,n,r=[],s=[]){n=n.concat(r),e.setValidators(e=>t.call(this)?i.A.compose(n)(e):r.length>0?i.A.compose(r)(e):null),s.forEach(t=>{t.valueChanges.subscribe(()=>{e.updateValueAndValidity({emitEvent:!1})})})}static match(e,t){return n=>{const i=n.get(e),r=n.get(t);if(!i||!r)return null;if(i.value!==r.value)r.setErrors({match:!0});else if(r.hasError("match")){const e=r.errors;s.a.unset(e,"match"),r.setErrors(s.a.isEmpty(s.a.keys(e))?null:e)}return null}}static unique(e,t=null,n,i=!1){let r;return d=>d.pristine||f(d.value)?Object(o.a)(null):(r=d.value,s.a.isFunction(n)&&null!==n()&&""!==n()&&(r=i?`${d.value}$${n()}`:`${n()}$${d.value}`),Object(a.a)().pipe(Object(c.a)(e.call(t,r)),Object(l.a)(e=>e?{notUnique:!0}:null),Object(u.a)(1)))}static uuid(e=!1){const t=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;return n=>n.pristine&&n.untouched?null:e||n.value?t.test(n.value)?null:{invalidUuid:"This is not a valid UUID"}:null}static binaryMin(e){return t=>{const n=new h.a,i=(new h.a).toBytes(t.value);if(e<=i)return null;const r=new d.a(n).transform(e);return{binaryMin:()=>"Size has to be at least " + r + " or more"}}}static binaryMax(e){return t=>{const n=new h.a,i=n.toBytes(t.value);if(e>=i)return null;const r=new d.a(n).transform(e);return{binaryMax:()=>"Size has to be at most " + r + " or less"}}}static passwordPolicy(e,t,n){return i=>{if(i.pristine||""===i.value)return s.a.isFunction(n)&&n(!0,0),Object(o.a)(null);let r;return s.a.isFunction(t)&&(r=t()),Object(a.a)(500).pipe(Object(c.a)(s.a.invoke(e,"validatePassword",i.value,r)),Object(l.a)(e=>(s.a.isFunction(n)&&n(e.valid,e.credits,e.valuation),e.valid?null:{passwordPolicy:!0})),Object(u.a)(1))}}}},"1Y/n":function(e,t,n){var i=n("HAuM"),r=n("ewvW"),s=n("RK3t"),o=n("UMSQ"),a=function(e){return function(t,n,a,c){i(n);var l=r(t),u=s(l),d=o(l.length),h=e?d-1:0,f=e?-1:1;if(a<2)for(;;){if(h in u){c=u[h],h+=f;break}if(h+=f,e?h<0:d<=h)throw TypeError("Reduce of empty array with no initial value")}for(;e?h>=0:d>h;h+=f)h in u&&(c=n(c,u[h],h,l));return c}};e.exports={left:a(!1),right:a(!0)}},"1nQr":function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("LvDl"),r=n.n(i),s=n("lJxs"),o=n("20UP");class a{constructor(e){this.pwdPolicyEnabled=e.pwd_policy_enabled,this.pwdPolicyMinLength=e.pwd_policy_min_length,this.pwdPolicyCheckLengthEnabled=e.pwd_policy_check_length_enabled,this.pwdPolicyCheckOldpwdEnabled=e.pwd_policy_check_oldpwd_enabled,this.pwdPolicyCheckUsernameEnabled=e.pwd_policy_check_username_enabled,this.pwdPolicyCheckExclusionListEnabled=e.pwd_policy_check_exclusion_list_enabled,this.pwdPolicyCheckRepetitiveCharsEnabled=e.pwd_policy_check_repetitive_chars_enabled,this.pwdPolicyCheckSequentialCharsEnabled=e.pwd_policy_check_sequential_chars_enabled,this.pwdPolicyCheckComplexityEnabled=e.pwd_policy_check_complexity_enabled}}var c=n("8Y7J");let l=(()=>{class e{constructor(e){this.settingsService=e}getHelpText(){return this.settingsService.getStandardSettings().pipe(Object(s.a)(e=>{const t=new a(e);let n=[];if(t.pwdPolicyEnabled){n.push("Required rules for passwords:");const e={pwdPolicyCheckLengthEnabled:"Must contain at least " + t.pwdPolicyMinLength + " characters",pwdPolicyCheckOldpwdEnabled:"Must not be the same as the previous one",pwdPolicyCheckUsernameEnabled:"Cannot contain the username",pwdPolicyCheckExclusionListEnabled:"Cannot contain any configured keyword",pwdPolicyCheckRepetitiveCharsEnabled:"Cannot contain any repetitive characters e.g. \"aaa\"",pwdPolicyCheckSequentialCharsEnabled:"Cannot contain any sequential characters e.g. \"abc\"",pwdPolicyCheckComplexityEnabled:"Must consist of characters from the following groups:\n * Alphabetic a-z, A-Z\n * Numbers 0-9\n * Special chars: !\"#$%& '()*+,-./:;<=>?@[\\]^_`{{|}}~\n * Any other characters (signs)"};n=n.concat(r.a.keys(e).filter(e=>r.a.get(t,e)).map(t=>"- "+r.a.get(e,t)))}return n.join("\n")}))}mapCreditsToCssClass(e){let t="very-strong";return e<10?t="too-weak":e<15?t="weak":e<20?t="ok":e<25&&(t="strong"),t}}return e.\u0275fac=function(t){return new(t||e)(c.dc(o.a))},e.\u0275prov=c.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},"1ppg":function(e,t,n){!function(e){"use strict";e.defineLocale("fil",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(n("wd/R"))},"1rYy":function(e,t,n){!function(e){"use strict";e.defineLocale("hy-am",{months:{format:"\u0570\u0578\u0582\u0576\u057e\u0561\u0580\u056b_\u0583\u0565\u057f\u0580\u057e\u0561\u0580\u056b_\u0574\u0561\u0580\u057f\u056b_\u0561\u057a\u0580\u056b\u056c\u056b_\u0574\u0561\u0575\u056b\u057d\u056b_\u0570\u0578\u0582\u0576\u056b\u057d\u056b_\u0570\u0578\u0582\u056c\u056b\u057d\u056b_\u0585\u0563\u0578\u057d\u057f\u0578\u057d\u056b_\u057d\u0565\u057a\u057f\u0565\u0574\u0562\u0565\u0580\u056b_\u0570\u0578\u056f\u057f\u0565\u0574\u0562\u0565\u0580\u056b_\u0576\u0578\u0575\u0565\u0574\u0562\u0565\u0580\u056b_\u0564\u0565\u056f\u057f\u0565\u0574\u0562\u0565\u0580\u056b".split("_"),standalone:"\u0570\u0578\u0582\u0576\u057e\u0561\u0580_\u0583\u0565\u057f\u0580\u057e\u0561\u0580_\u0574\u0561\u0580\u057f_\u0561\u057a\u0580\u056b\u056c_\u0574\u0561\u0575\u056b\u057d_\u0570\u0578\u0582\u0576\u056b\u057d_\u0570\u0578\u0582\u056c\u056b\u057d_\u0585\u0563\u0578\u057d\u057f\u0578\u057d_\u057d\u0565\u057a\u057f\u0565\u0574\u0562\u0565\u0580_\u0570\u0578\u056f\u057f\u0565\u0574\u0562\u0565\u0580_\u0576\u0578\u0575\u0565\u0574\u0562\u0565\u0580_\u0564\u0565\u056f\u057f\u0565\u0574\u0562\u0565\u0580".split("_")},monthsShort:"\u0570\u0576\u057e_\u0583\u057f\u0580_\u0574\u0580\u057f_\u0561\u057a\u0580_\u0574\u0575\u057d_\u0570\u0576\u057d_\u0570\u056c\u057d_\u0585\u0563\u057d_\u057d\u057a\u057f_\u0570\u056f\u057f_\u0576\u0574\u0562_\u0564\u056f\u057f".split("_"),weekdays:"\u056f\u056b\u0580\u0561\u056f\u056b_\u0565\u0580\u056f\u0578\u0582\u0577\u0561\u0562\u0569\u056b_\u0565\u0580\u0565\u0584\u0577\u0561\u0562\u0569\u056b_\u0579\u0578\u0580\u0565\u0584\u0577\u0561\u0562\u0569\u056b_\u0570\u056b\u0576\u0563\u0577\u0561\u0562\u0569\u056b_\u0578\u0582\u0580\u0562\u0561\u0569_\u0577\u0561\u0562\u0561\u0569".split("_"),weekdaysShort:"\u056f\u0580\u056f_\u0565\u0580\u056f_\u0565\u0580\u0584_\u0579\u0580\u0584_\u0570\u0576\u0563_\u0578\u0582\u0580\u0562_\u0577\u0562\u0569".split("_"),weekdaysMin:"\u056f\u0580\u056f_\u0565\u0580\u056f_\u0565\u0580\u0584_\u0579\u0580\u0584_\u0570\u0576\u0563_\u0578\u0582\u0580\u0562_\u0577\u0562\u0569".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY \u0569.",LLL:"D MMMM YYYY \u0569., HH:mm",LLLL:"dddd, D MMMM YYYY \u0569., HH:mm"},calendar:{sameDay:"[\u0561\u0575\u057d\u0585\u0580] LT",nextDay:"[\u057e\u0561\u0572\u0568] LT",lastDay:"[\u0565\u0580\u0565\u056f] LT",nextWeek:function(){return"dddd [\u0585\u0580\u0568 \u056a\u0561\u0574\u0568] LT"},lastWeek:function(){return"[\u0561\u0576\u0581\u0561\u056e] dddd [\u0585\u0580\u0568 \u056a\u0561\u0574\u0568] LT"},sameElse:"L"},relativeTime:{future:"%s \u0570\u0565\u057f\u0578",past:"%s \u0561\u057c\u0561\u057b",s:"\u0574\u056b \u0584\u0561\u0576\u056b \u057e\u0561\u0575\u0580\u056f\u0575\u0561\u0576",ss:"%d \u057e\u0561\u0575\u0580\u056f\u0575\u0561\u0576",m:"\u0580\u0578\u057a\u0565",mm:"%d \u0580\u0578\u057a\u0565",h:"\u056a\u0561\u0574",hh:"%d \u056a\u0561\u0574",d:"\u0585\u0580",dd:"%d \u0585\u0580",M:"\u0561\u0574\u056b\u057d",MM:"%d \u0561\u0574\u056b\u057d",y:"\u057f\u0561\u0580\u056b",yy:"%d \u057f\u0561\u0580\u056b"},meridiemParse:/\u0563\u056b\u0577\u0565\u0580\u057e\u0561|\u0561\u057c\u0561\u057e\u0578\u057f\u057e\u0561|\u0581\u0565\u0580\u0565\u056f\u057e\u0561|\u0565\u0580\u0565\u056f\u0578\u0575\u0561\u0576/,isPM:function(e){return/^(\u0581\u0565\u0580\u0565\u056f\u057e\u0561|\u0565\u0580\u0565\u056f\u0578\u0575\u0561\u0576)$/.test(e)},meridiem:function(e){return e<4?"\u0563\u056b\u0577\u0565\u0580\u057e\u0561":e<12?"\u0561\u057c\u0561\u057e\u0578\u057f\u057e\u0561":e<17?"\u0581\u0565\u0580\u0565\u056f\u057e\u0561":"\u0565\u0580\u0565\u056f\u0578\u0575\u0561\u0576"},dayOfMonthOrdinalParse:/\d{1,2}|\d{1,2}-(\u056b\u0576|\u0580\u0564)/,ordinal:function(e,t){switch(t){case"DDD":case"w":case"W":case"DDDo":return 1===e?e+"-\u056b\u0576":e+"-\u0580\u0564";default:return e}},week:{dow:1,doy:7}})}(n("wd/R"))},"1xZ4":function(e,t,n){!function(e){"use strict";e.defineLocale("ca",{months:{standalone:"gener_febrer_mar\xe7_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),format:"de gener_de febrer_de mar\xe7_d'abril_de maig_de juny_de juliol_d'agost_de setembre_d'octubre_de novembre_de desembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._mar\xe7_abr._maig_juny_jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dt_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a les] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a les] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[dem\xe0 a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"d'aqu\xed %s",past:"fa %s",s:"uns segons",ss:"%d segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|\xe8|a)/,ordinal:function(e,t){var n=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"\xe8";return"w"!==t&&"W"!==t||(n="a"),e+n},week:{dow:1,doy:4}})}(n("wd/R"))},"20UP":function(e,t,n){"use strict";n.d(t,"a",(function(){return c}));var i=n("LvDl"),r=n.n(i),s=n("lJxs"),o=n("8Y7J"),a=n("IheW");let c=(()=>{class e{constructor(e){this.http=e,this.settings={}}getValues(e){return r.a.isArray(e)&&(e=e.join(",")),this.http.get("api/settings?names="+e).pipe(Object(s.a)(e=>{const t={};return r.a.forEach(e,e=>{r.a.set(t,e.name,e.value)}),t}))}ifSettingConfigured(e,t,n){const i=this.settings[e];void 0===i?this.http.get(e).subscribe(i=>{this.settings[e]=this.getSettingsValue(i),this.ifSettingConfigured(e,t,n)},t=>{401!==t.status&&(this.settings[e]="")}):""!==i?t(i):n&&n()}disableSetting(e){this.settings[e]=""}getSettingsValue(e){return e.value||e.instance||""}validateGrafanaDashboardUrl(e){return this.http.get("api/grafana/validation/"+e)}getStandardSettings(){return this.http.get("ui-api/standard_settings")}}return e.\u0275fac=function(t){return new(t||e)(o.dc(a.b))},e.\u0275prov=o.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},"23KU":function(e,t,n){"use strict";var i=n("uE2L"),r=n("YHEm"),s=Object.prototype.hasOwnProperty;t.a=function(e,t,n){var o=e[t];s.call(e,t)&&Object(r.a)(o,n)&&(void 0!==n||t in e)||Object(i.a)(e,t,n)}},"25cm":function(e,t,n){"use strict";var i=n("tPH9"),r=n("/1FC");t.a=function(e,t,n){var s=t(e);return Object(r.a)(e)?s:Object(i.a)(s,n(e))}},"2EZI":function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("s7LF"),r=n("QFaf"),s=n("8Y7J");let o=(()=>{class e extends i.g{group(e,t=null){const n=super.group(e,t);return new r.a(n.controls,n.validator,n.asyncValidator)}}return e.\u0275fac=function(t){return a(t||e)},e.\u0275prov=s.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();const a=s.Ub(o)},"2QA8":function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));const i=(()=>"function"==typeof Symbol?Symbol("rxSubscriber"):"@@rxSubscriber_"+Math.random())()},"2Vo4":function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("XNiG"),r=n("9ppp");class s extends i.a{constructor(e){super(),this._value=e}get value(){return this.getValue()}_subscribe(e){const t=super._subscribe(e);return t&&!t.closed&&e.next(this._value),t}getValue(){if(this.hasError)throw this.thrownError;if(this.closed)throw new r.a;return this._value}next(e){super.next(this._value=e)}}},"2fFW":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));let i=!1;const r={Promise:void 0,set useDeprecatedSynchronousErrorHandling(e){if(e){const e=new Error;console.warn("DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n"+e.stack)}else i&&console.log("RxJS: Back to a better error behavior. Thank you. <3");i=e},get useDeprecatedSynchronousErrorHandling(){return i}}},"2fjn":function(e,t,n){!function(e){"use strict";e.defineLocale("fr-ca",{months:"janvier_f\xe9vrier_mars_avril_mai_juin_juillet_ao\xfbt_septembre_octobre_novembre_d\xe9cembre".split("_"),monthsShort:"janv._f\xe9vr._mars_avr._mai_juin_juil._ao\xfbt_sept._oct._nov._d\xe9c.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd\u2019hui \xe0] LT",nextDay:"[Demain \xe0] LT",nextWeek:"dddd [\xe0] LT",lastDay:"[Hier \xe0] LT",lastWeek:"dddd [dernier \xe0] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,t){switch(t){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}}})}(n("wd/R"))},"2oRo":function(e,t){var n=function(e){return e&&e.Math==Math&&e};e.exports=n("object"==typeof globalThis&&globalThis)||n("object"==typeof window&&window)||n("object"==typeof self&&self)||n("object"==typeof global&&global)||function(){return this}()||Function("return this")()},"2ykv":function(e,t,n){!function(e){"use strict";var t="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),n="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),i=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],r=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,i){return e?/-MMM-/.test(i)?n[e.month()]:t[e.month()]:t},monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"\xe9\xe9n minuut",mm:"%d minuten",h:"\xe9\xe9n uur",hh:"%d uur",d:"\xe9\xe9n dag",dd:"%d dagen",M:"\xe9\xe9n maand",MM:"%d maanden",y:"\xe9\xe9n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(n("wd/R"))},"3/ER":function(e,t,n){"use strict";(function(e){var i=n("Ju5/"),r="object"==typeof exports&&exports&&!exports.nodeType&&exports,s=r&&"object"==typeof e&&e&&!e.nodeType&&e,o=s&&s.exports===r?i.a.Buffer:void 0,a=o?o.allocUnsafe:void 0;t.a=function(e,t){if(t)return e.slice();var n=e.length,i=a?a(n):new e.constructor(n);return e.copy(i),i}}).call(this,n("3UD+")(e))},"33Wh":function(e,t,n){var i=n("yoRg"),r=n("eDl+");e.exports=Object.keys||function(e){return i(e,r)}},"3E0/":function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("D0XW"),r=n("7o/Q"),s=n("WMd4");function o(e,t=i.a){var n;const r=(n=e)instanceof Date&&!isNaN(+n)?+e-t.now():Math.abs(e);return e=>e.lift(new a(r,t))}class a{constructor(e,t){this.delay=e,this.scheduler=t}call(e,t){return t.subscribe(new c(e,this.delay,this.scheduler))}}class c extends r.a{constructor(e,t,n){super(e),this.delay=t,this.scheduler=n,this.queue=[],this.active=!1,this.errored=!1}static dispatch(e){const t=e.source,n=t.queue,i=e.scheduler,r=e.destination;for(;n.length>0&&n[0].time-i.now()<=0;)n.shift().notification.observe(r);if(n.length>0){const t=Math.max(0,n[0].time-i.now());this.schedule(e,t)}else this.unsubscribe(),t.active=!1}_schedule(e){this.active=!0,this.destination.add(e.schedule(c.dispatch,this.delay,{source:this,destination:this.destination,scheduler:e}))}scheduleNotification(e){if(!0===this.errored)return;const t=this.scheduler,n=new l(t.now()+this.delay,e);this.queue.push(n),!1===this.active&&this._schedule(t)}_next(e){this.scheduleNotification(s.a.createNext(e))}_error(e){this.errored=!0,this.queue=[],this.destination.error(e),this.unsubscribe()}_complete(){this.scheduleNotification(s.a.createComplete()),this.unsubscribe()}}class l{constructor(e,t){this.time=e,this.notification=t}}},"3E1r":function(e,t,n){!function(e){"use strict";var t={1:"\u0967",2:"\u0968",3:"\u0969",4:"\u096a",5:"\u096b",6:"\u096c",7:"\u096d",8:"\u096e",9:"\u096f",0:"\u0966"},n={"\u0967":"1","\u0968":"2","\u0969":"3","\u096a":"4","\u096b":"5","\u096c":"6","\u096d":"7","\u096e":"8","\u096f":"9","\u0966":"0"},i=[/^\u091c\u0928/i,/^\u092b\u093c\u0930|\u092b\u0930/i,/^\u092e\u093e\u0930\u094d\u091a/i,/^\u0905\u092a\u094d\u0930\u0948/i,/^\u092e\u0908/i,/^\u091c\u0942\u0928/i,/^\u091c\u0941\u0932/i,/^\u0905\u0917/i,/^\u0938\u093f\u0924\u0902|\u0938\u093f\u0924/i,/^\u0905\u0915\u094d\u091f\u0942/i,/^\u0928\u0935|\u0928\u0935\u0902/i,/^\u0926\u093f\u0938\u0902|\u0926\u093f\u0938/i];e.defineLocale("hi",{months:{format:"\u091c\u0928\u0935\u0930\u0940_\u092b\u093c\u0930\u0935\u0930\u0940_\u092e\u093e\u0930\u094d\u091a_\u0905\u092a\u094d\u0930\u0948\u0932_\u092e\u0908_\u091c\u0942\u0928_\u091c\u0941\u0932\u093e\u0908_\u0905\u0917\u0938\u094d\u0924_\u0938\u093f\u0924\u092e\u094d\u092c\u0930_\u0905\u0915\u094d\u091f\u0942\u092c\u0930_\u0928\u0935\u092e\u094d\u092c\u0930_\u0926\u093f\u0938\u092e\u094d\u092c\u0930".split("_"),standalone:"\u091c\u0928\u0935\u0930\u0940_\u092b\u0930\u0935\u0930\u0940_\u092e\u093e\u0930\u094d\u091a_\u0905\u092a\u094d\u0930\u0948\u0932_\u092e\u0908_\u091c\u0942\u0928_\u091c\u0941\u0932\u093e\u0908_\u0905\u0917\u0938\u094d\u0924_\u0938\u093f\u0924\u0902\u092c\u0930_\u0905\u0915\u094d\u091f\u0942\u092c\u0930_\u0928\u0935\u0902\u092c\u0930_\u0926\u093f\u0938\u0902\u092c\u0930".split("_")},monthsShort:"\u091c\u0928._\u092b\u093c\u0930._\u092e\u093e\u0930\u094d\u091a_\u0905\u092a\u094d\u0930\u0948._\u092e\u0908_\u091c\u0942\u0928_\u091c\u0941\u0932._\u0905\u0917._\u0938\u093f\u0924._\u0905\u0915\u094d\u091f\u0942._\u0928\u0935._\u0926\u093f\u0938.".split("_"),weekdays:"\u0930\u0935\u093f\u0935\u093e\u0930_\u0938\u094b\u092e\u0935\u093e\u0930_\u092e\u0902\u0917\u0932\u0935\u093e\u0930_\u092c\u0941\u0927\u0935\u093e\u0930_\u0917\u0941\u0930\u0942\u0935\u093e\u0930_\u0936\u0941\u0915\u094d\u0930\u0935\u093e\u0930_\u0936\u0928\u093f\u0935\u093e\u0930".split("_"),weekdaysShort:"\u0930\u0935\u093f_\u0938\u094b\u092e_\u092e\u0902\u0917\u0932_\u092c\u0941\u0927_\u0917\u0941\u0930\u0942_\u0936\u0941\u0915\u094d\u0930_\u0936\u0928\u093f".split("_"),weekdaysMin:"\u0930_\u0938\u094b_\u092e\u0902_\u092c\u0941_\u0917\u0941_\u0936\u0941_\u0936".split("_"),longDateFormat:{LT:"A h:mm \u092c\u091c\u0947",LTS:"A h:mm:ss \u092c\u091c\u0947",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm \u092c\u091c\u0947",LLLL:"dddd, D MMMM YYYY, A h:mm \u092c\u091c\u0947"},monthsParse:i,longMonthsParse:i,shortMonthsParse:[/^\u091c\u0928/i,/^\u092b\u093c\u0930/i,/^\u092e\u093e\u0930\u094d\u091a/i,/^\u0905\u092a\u094d\u0930\u0948/i,/^\u092e\u0908/i,/^\u091c\u0942\u0928/i,/^\u091c\u0941\u0932/i,/^\u0905\u0917/i,/^\u0938\u093f\u0924/i,/^\u0905\u0915\u094d\u091f\u0942/i,/^\u0928\u0935/i,/^\u0926\u093f\u0938/i],monthsRegex:/^(\u091c\u0928\u0935\u0930\u0940|\u091c\u0928\.?|\u092b\u093c\u0930\u0935\u0930\u0940|\u092b\u0930\u0935\u0930\u0940|\u092b\u093c\u0930\.?|\u092e\u093e\u0930\u094d\u091a?|\u0905\u092a\u094d\u0930\u0948\u0932|\u0905\u092a\u094d\u0930\u0948\.?|\u092e\u0908?|\u091c\u0942\u0928?|\u091c\u0941\u0932\u093e\u0908|\u091c\u0941\u0932\.?|\u0905\u0917\u0938\u094d\u0924|\u0905\u0917\.?|\u0938\u093f\u0924\u092e\u094d\u092c\u0930|\u0938\u093f\u0924\u0902\u092c\u0930|\u0938\u093f\u0924\.?|\u0905\u0915\u094d\u091f\u0942\u092c\u0930|\u0905\u0915\u094d\u091f\u0942\.?|\u0928\u0935\u092e\u094d\u092c\u0930|\u0928\u0935\u0902\u092c\u0930|\u0928\u0935\.?|\u0926\u093f\u0938\u092e\u094d\u092c\u0930|\u0926\u093f\u0938\u0902\u092c\u0930|\u0926\u093f\u0938\.?)/i,monthsShortRegex:/^(\u091c\u0928\u0935\u0930\u0940|\u091c\u0928\.?|\u092b\u093c\u0930\u0935\u0930\u0940|\u092b\u0930\u0935\u0930\u0940|\u092b\u093c\u0930\.?|\u092e\u093e\u0930\u094d\u091a?|\u0905\u092a\u094d\u0930\u0948\u0932|\u0905\u092a\u094d\u0930\u0948\.?|\u092e\u0908?|\u091c\u0942\u0928?|\u091c\u0941\u0932\u093e\u0908|\u091c\u0941\u0932\.?|\u0905\u0917\u0938\u094d\u0924|\u0905\u0917\.?|\u0938\u093f\u0924\u092e\u094d\u092c\u0930|\u0938\u093f\u0924\u0902\u092c\u0930|\u0938\u093f\u0924\.?|\u0905\u0915\u094d\u091f\u0942\u092c\u0930|\u0905\u0915\u094d\u091f\u0942\.?|\u0928\u0935\u092e\u094d\u092c\u0930|\u0928\u0935\u0902\u092c\u0930|\u0928\u0935\.?|\u0926\u093f\u0938\u092e\u094d\u092c\u0930|\u0926\u093f\u0938\u0902\u092c\u0930|\u0926\u093f\u0938\.?)/i,monthsStrictRegex:/^(\u091c\u0928\u0935\u0930\u0940?|\u092b\u093c\u0930\u0935\u0930\u0940|\u092b\u0930\u0935\u0930\u0940?|\u092e\u093e\u0930\u094d\u091a?|\u0905\u092a\u094d\u0930\u0948\u0932?|\u092e\u0908?|\u091c\u0942\u0928?|\u091c\u0941\u0932\u093e\u0908?|\u0905\u0917\u0938\u094d\u0924?|\u0938\u093f\u0924\u092e\u094d\u092c\u0930|\u0938\u093f\u0924\u0902\u092c\u0930|\u0938\u093f\u0924?\.?|\u0905\u0915\u094d\u091f\u0942\u092c\u0930|\u0905\u0915\u094d\u091f\u0942\.?|\u0928\u0935\u092e\u094d\u092c\u0930|\u0928\u0935\u0902\u092c\u0930?|\u0926\u093f\u0938\u092e\u094d\u092c\u0930|\u0926\u093f\u0938\u0902\u092c\u0930?)/i,monthsShortStrictRegex:/^(\u091c\u0928\.?|\u092b\u093c\u0930\.?|\u092e\u093e\u0930\u094d\u091a?|\u0905\u092a\u094d\u0930\u0948\.?|\u092e\u0908?|\u091c\u0942\u0928?|\u091c\u0941\u0932\.?|\u0905\u0917\.?|\u0938\u093f\u0924\.?|\u0905\u0915\u094d\u091f\u0942\.?|\u0928\u0935\.?|\u0926\u093f\u0938\.?)/i,calendar:{sameDay:"[\u0906\u091c] LT",nextDay:"[\u0915\u0932] LT",nextWeek:"dddd, LT",lastDay:"[\u0915\u0932] LT",lastWeek:"[\u092a\u093f\u091b\u0932\u0947] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u092e\u0947\u0902",past:"%s \u092a\u0939\u0932\u0947",s:"\u0915\u0941\u091b \u0939\u0940 \u0915\u094d\u0937\u0923",ss:"%d \u0938\u0947\u0915\u0902\u0921",m:"\u090f\u0915 \u092e\u093f\u0928\u091f",mm:"%d \u092e\u093f\u0928\u091f",h:"\u090f\u0915 \u0918\u0902\u091f\u093e",hh:"%d \u0918\u0902\u091f\u0947",d:"\u090f\u0915 \u0926\u093f\u0928",dd:"%d \u0926\u093f\u0928",M:"\u090f\u0915 \u092e\u0939\u0940\u0928\u0947",MM:"%d \u092e\u0939\u0940\u0928\u0947",y:"\u090f\u0915 \u0935\u0930\u094d\u0937",yy:"%d \u0935\u0930\u094d\u0937"},preparse:function(e){return e.replace(/[\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u0966]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0930\u093e\u0924|\u0938\u0941\u092c\u0939|\u0926\u094b\u092a\u0939\u0930|\u0936\u093e\u092e/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0930\u093e\u0924"===t?e<4?e:e+12:"\u0938\u0941\u092c\u0939"===t?e:"\u0926\u094b\u092a\u0939\u0930"===t?e>=10?e:e+12:"\u0936\u093e\u092e"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"\u0930\u093e\u0924":e<10?"\u0938\u0941\u092c\u0939":e<17?"\u0926\u094b\u092a\u0939\u0930":e<20?"\u0936\u093e\u092e":"\u0930\u093e\u0924"},week:{dow:0,doy:6}})}(n("wd/R"))},"3N8a":function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("quSY");class r extends i.a{constructor(e,t){super()}schedule(e,t=0){return this}}class s extends r{constructor(e,t){super(e,t),this.scheduler=e,this.work=t,this.pending=!1}schedule(e,t=0){if(this.closed)return this;this.state=e;const n=this.id,i=this.scheduler;return null!=n&&(this.id=this.recycleAsyncId(i,n,t)),this.pending=!0,this.delay=t,this.id=this.id||this.requestAsyncId(i,this.id,t),this}requestAsyncId(e,t,n=0){return setInterval(e.flush.bind(e,this),n)}recycleAsyncId(e,t,n=0){if(null!==n&&this.delay===n&&!1===this.pending)return t;clearInterval(t)}execute(e,t){if(this.closed)return new Error("executing a cancelled action");this.pending=!1;const n=this._execute(e,t);if(n)return n;!1===this.pending&&null!=this.id&&(this.id=this.recycleAsyncId(this.scheduler,this.id,null))}_execute(e,t){let n=!1,i=void 0;try{this.work(e)}catch(r){n=!0,i=!!r&&r||new Error(r)}if(n)return this.unsubscribe(),i}_unsubscribe(){const e=this.id,t=this.scheduler,n=t.actions,i=n.indexOf(this);this.work=null,this.state=null,this.pending=!1,this.scheduler=null,-1!==i&&n.splice(i,1),null!=e&&(this.id=this.recycleAsyncId(t,e,null)),this.delay=null}}},"3UD+":function(e,t){e.exports=function(e){if(!e.webpackPolyfill){var t=Object.create(e);t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),Object.defineProperty(t,"exports",{enumerable:!0}),t.webpackPolyfill=1}return t}},"3bBZ":function(e,t,n){var i=n("2oRo"),r=n("/byt"),s=n("4mDm"),o=n("kRJp"),a=n("tiKp"),c=a("iterator"),l=a("toStringTag"),u=s.values;for(var d in r){var h=i[d],f=h&&h.prototype;if(f){if(f[c]!==u)try{o(f,c,u)}catch(m){f[c]=u}if(f[l]||o(f,l,d),r[d])for(var p in s)if(f[p]!==s[p])try{o(f,p,s[p])}catch(m){f[p]=s[p]}}}},"3cmB":function(e,t,n){"use strict";var i=n("Y7yP"),r=n("Ju5/"),s=Object(i.a)(r.a,"Map");t.a=s},"4/q3":function(e,t,n){"use strict";var i=n("7gMY"),r=n("IzLi"),s=n("pyRK"),o=Object.prototype.hasOwnProperty,a=n("5WsY");t.a=function(e){return Object(a.a)(e)?Object(i.a)(e,!0):function(e){if(!Object(r.a)(e))return function(e){var t=[];if(null!=e)for(var n in Object(e))t.push(n);return t}(e);var t=Object(s.a)(e),n=[];for(var i in e)("constructor"!=i||!t&&o.call(e,i))&&n.push(i);return n}(e)}},"4DD9":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){let t=!1;switch(e){case!0:case 1:case"y":case"yes":case"t":case"true":case"on":case"1":t=!0}return t}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"boolean",type:e,pure:!0}),e})()},"4I5i":function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));const i=(()=>{function e(){return Error.call(this),this.message="argument out of range",this.name="ArgumentOutOfRangeError",this}return e.prototype=Object.create(Error.prototype),e})()},"4MV3":function(e,t,n){!function(e){"use strict";var t={1:"\u0ae7",2:"\u0ae8",3:"\u0ae9",4:"\u0aea",5:"\u0aeb",6:"\u0aec",7:"\u0aed",8:"\u0aee",9:"\u0aef",0:"\u0ae6"},n={"\u0ae7":"1","\u0ae8":"2","\u0ae9":"3","\u0aea":"4","\u0aeb":"5","\u0aec":"6","\u0aed":"7","\u0aee":"8","\u0aef":"9","\u0ae6":"0"};e.defineLocale("gu",{months:"\u0a9c\u0abe\u0aa8\u0acd\u0aaf\u0ac1\u0a86\u0ab0\u0ac0_\u0aab\u0ac7\u0aac\u0acd\u0ab0\u0ac1\u0a86\u0ab0\u0ac0_\u0aae\u0abe\u0ab0\u0acd\u0a9a_\u0a8f\u0aaa\u0acd\u0ab0\u0abf\u0ab2_\u0aae\u0ac7_\u0a9c\u0ac2\u0aa8_\u0a9c\u0ac1\u0ab2\u0abe\u0a88_\u0a91\u0a97\u0ab8\u0acd\u0a9f_\u0ab8\u0aaa\u0acd\u0a9f\u0ac7\u0aae\u0acd\u0aac\u0ab0_\u0a91\u0a95\u0acd\u0a9f\u0acd\u0aac\u0ab0_\u0aa8\u0ab5\u0ac7\u0aae\u0acd\u0aac\u0ab0_\u0aa1\u0abf\u0ab8\u0ac7\u0aae\u0acd\u0aac\u0ab0".split("_"),monthsShort:"\u0a9c\u0abe\u0aa8\u0acd\u0aaf\u0ac1._\u0aab\u0ac7\u0aac\u0acd\u0ab0\u0ac1._\u0aae\u0abe\u0ab0\u0acd\u0a9a_\u0a8f\u0aaa\u0acd\u0ab0\u0abf._\u0aae\u0ac7_\u0a9c\u0ac2\u0aa8_\u0a9c\u0ac1\u0ab2\u0abe._\u0a91\u0a97._\u0ab8\u0aaa\u0acd\u0a9f\u0ac7._\u0a91\u0a95\u0acd\u0a9f\u0acd._\u0aa8\u0ab5\u0ac7._\u0aa1\u0abf\u0ab8\u0ac7.".split("_"),monthsParseExact:!0,weekdays:"\u0ab0\u0ab5\u0abf\u0ab5\u0abe\u0ab0_\u0ab8\u0acb\u0aae\u0ab5\u0abe\u0ab0_\u0aae\u0a82\u0a97\u0ab3\u0ab5\u0abe\u0ab0_\u0aac\u0ac1\u0aa7\u0acd\u0ab5\u0abe\u0ab0_\u0a97\u0ac1\u0ab0\u0ac1\u0ab5\u0abe\u0ab0_\u0ab6\u0ac1\u0a95\u0acd\u0ab0\u0ab5\u0abe\u0ab0_\u0ab6\u0aa8\u0abf\u0ab5\u0abe\u0ab0".split("_"),weekdaysShort:"\u0ab0\u0ab5\u0abf_\u0ab8\u0acb\u0aae_\u0aae\u0a82\u0a97\u0ab3_\u0aac\u0ac1\u0aa7\u0acd_\u0a97\u0ac1\u0ab0\u0ac1_\u0ab6\u0ac1\u0a95\u0acd\u0ab0_\u0ab6\u0aa8\u0abf".split("_"),weekdaysMin:"\u0ab0_\u0ab8\u0acb_\u0aae\u0a82_\u0aac\u0ac1_\u0a97\u0ac1_\u0ab6\u0ac1_\u0ab6".split("_"),longDateFormat:{LT:"A h:mm \u0ab5\u0abe\u0a97\u0acd\u0aaf\u0ac7",LTS:"A h:mm:ss \u0ab5\u0abe\u0a97\u0acd\u0aaf\u0ac7",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm \u0ab5\u0abe\u0a97\u0acd\u0aaf\u0ac7",LLLL:"dddd, D MMMM YYYY, A h:mm \u0ab5\u0abe\u0a97\u0acd\u0aaf\u0ac7"},calendar:{sameDay:"[\u0a86\u0a9c] LT",nextDay:"[\u0a95\u0abe\u0ab2\u0ac7] LT",nextWeek:"dddd, LT",lastDay:"[\u0a97\u0a87\u0a95\u0abe\u0ab2\u0ac7] LT",lastWeek:"[\u0aaa\u0abe\u0a9b\u0ab2\u0abe] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0aae\u0abe",past:"%s \u0aaa\u0ab9\u0ac7\u0ab2\u0abe",s:"\u0a85\u0aae\u0ac1\u0a95 \u0aaa\u0ab3\u0acb",ss:"%d \u0ab8\u0ac7\u0a95\u0a82\u0aa1",m:"\u0a8f\u0a95 \u0aae\u0abf\u0aa8\u0abf\u0a9f",mm:"%d \u0aae\u0abf\u0aa8\u0abf\u0a9f",h:"\u0a8f\u0a95 \u0a95\u0ab2\u0abe\u0a95",hh:"%d \u0a95\u0ab2\u0abe\u0a95",d:"\u0a8f\u0a95 \u0aa6\u0abf\u0ab5\u0ab8",dd:"%d \u0aa6\u0abf\u0ab5\u0ab8",M:"\u0a8f\u0a95 \u0aae\u0ab9\u0abf\u0aa8\u0acb",MM:"%d \u0aae\u0ab9\u0abf\u0aa8\u0acb",y:"\u0a8f\u0a95 \u0ab5\u0ab0\u0acd\u0ab7",yy:"%d \u0ab5\u0ab0\u0acd\u0ab7"},preparse:function(e){return e.replace(/[\u0ae7\u0ae8\u0ae9\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef\u0ae6]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0ab0\u0abe\u0aa4|\u0aac\u0aaa\u0acb\u0ab0|\u0ab8\u0ab5\u0abe\u0ab0|\u0ab8\u0abe\u0a82\u0a9c/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0ab0\u0abe\u0aa4"===t?e<4?e:e+12:"\u0ab8\u0ab5\u0abe\u0ab0"===t?e:"\u0aac\u0aaa\u0acb\u0ab0"===t?e>=10?e:e+12:"\u0ab8\u0abe\u0a82\u0a9c"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"\u0ab0\u0abe\u0aa4":e<10?"\u0ab8\u0ab5\u0abe\u0ab0":e<17?"\u0aac\u0aaa\u0acb\u0ab0":e<20?"\u0ab8\u0abe\u0a82\u0a9c":"\u0ab0\u0abe\u0aa4"},week:{dow:0,doy:6}})}(n("wd/R"))},"4WOD":function(e,t,n){var i=n("UTVS"),r=n("ewvW"),s=n("93I0"),o=n("4Xet"),a=s("IE_PROTO"),c=Object.prototype;e.exports=o?Object.getPrototypeOf:function(e){return e=r(e),i(e,a)?e[a]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?c:null}},"4Xet":function(e,t,n){var i=n("0Dky");e.exports=!i((function(){function e(){}return e.prototype.constructor=null,Object.getPrototypeOf(new e)!==e.prototype}))},"4dOw":function(e,t,n){!function(e){"use strict";e.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(n("wd/R"))},"4l63":function(e,t,n){var i=n("I+eb"),r=n("wg0c");i({global:!0,forced:parseInt!=r},{parseInt:r})},"4mDm":function(e,t,n){"use strict";var i=n("/GqU"),r=n("RNIs"),s=n("P4y1"),o=n("afO8"),a=n("fdAy"),c="Array Iterator",l=o.set,u=o.getterFor(c);e.exports=a(Array,"Array",(function(e,t){l(this,{type:c,target:i(e),index:0,kind:t})}),(function(){var e=u(this),t=e.target,n=e.kind,i=e.index++;return!t||i>=t.length?(e.target=void 0,{value:void 0,done:!0}):"keys"==n?{value:i,done:!1}:"values"==n?{value:t[i],done:!1}:{value:[i,t[i]],done:!1}}),"values"),s.Arguments=s.Array,r("keys"),r("values"),r("entries")},"4syw":function(e,t,n){var i=n("busE");e.exports=function(e,t,n){for(var r in t)i(e,r,t[r],n);return e}},"5+tZ":function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("lJxs"),r=n("Cfvw"),s=n("zx2A");function o(e,t,n=Number.POSITIVE_INFINITY){return"function"==typeof t?s=>s.pipe(o((n,s)=>Object(r.a)(e(n,s)).pipe(Object(i.a)((e,i)=>t(n,e,s,i))),n)):("number"==typeof t&&(n=t),t=>t.lift(new a(e,n)))}class a{constructor(e,t=Number.POSITIVE_INFINITY){this.project=e,this.concurrent=t}call(e,t){return t.subscribe(new c(e,this.project,this.concurrent))}}class c extends s.b{constructor(e,t,n=Number.POSITIVE_INFINITY){super(e),this.project=t,this.concurrent=n,this.hasCompleted=!1,this.buffer=[],this.active=0,this.index=0}_next(e){this.active0?this._next(e.shift()):0===this.active&&this.hasCompleted&&this.destination.complete()}}},"5WsY":function(e,t,n){"use strict";var i=n("vJtL"),r=n("Js68");t.a=function(e){return null!=e&&Object(r.a)(e.length)&&!Object(i.a)(e)}},"5yfJ":function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("HDdC"),r=n("KqfI");const s=new i.a(r.a)},"6+QB":function(e,t,n){!function(e){"use strict";e.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,t){return 12===e&&(e=0),"pagi"===t?e:"tengahari"===t?e>=11?e:e+12:"petang"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(n("wd/R"))},"6+kj":function(e,t,n){"use strict";n.d(t,"a",(function(){return u}));var i=n("8Y7J"),r=n("sne2"),s=n("JK/P"),o=n("sb0X"),a=n("SVse"),c=n("Z21x");function l(e,t){if(1&e){const e=i.Tb();i.Sb(0,"cd-submit-button",2),i.gc("submitAction",(function(){return i.Dc(e),i.ic().submitAction()})),i.Oc(1),i.Rb()}if(2&e){const e=i.ic();i.pc("disabled",e.disabled)("form",e.form),i.yb(1),i.Pc(e.submitText)}}let u=(()=>{class e{constructor(e,t,n){this.location=e,this.actionLabels=t,this.modalService=n,this.submitActionEvent=new i.o,this.backActionEvent=new i.o,this.showSubmit=!0,this.wrappingClass="",this.btnClass="",this.submitText=this.actionLabels.CREATE,this.cancelText=this.actionLabels.CANCEL,this.disabled=!1}submitAction(){this.submitActionEvent.emit()}backAction(){0===this.backActionEvent.observers.length?this.modalService.hasOpenModals()?this.modalService.dismissAll():this.location.back():this.backActionEvent.emit()}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(a.m),i.Mb(r.b),i.Mb(s.a))},e.\u0275cmp=i.Gb({type:e,selectors:[["cd-form-button-panel"]],viewQuery:function(e,t){var n;1&e&&i.Tc(o.a,!0),2&e&&i.zc(n=i.hc())&&(t.submitButton=n.first)},inputs:{form:"form",showSubmit:"showSubmit",wrappingClass:"wrappingClass",btnClass:"btnClass",submitText:"submitText",cancelText:"cancelText",disabled:"disabled"},outputs:{submitActionEvent:"submitActionEvent",backActionEvent:"backActionEvent"},decls:3,vars:4,consts:[[1,"m-2",3,"name","backAction"],["data-cy","submitBtn",3,"disabled","form","submitAction",4,"ngIf"],["data-cy","submitBtn",3,"disabled","form","submitAction"]],template:function(e,t){1&e&&(i.Sb(0,"div"),i.Sb(1,"cd-back-button",0),i.gc("backAction",(function(){return t.backAction()})),i.Rb(),i.Mc(2,l,2,3,"cd-submit-button",1),i.Rb()),2&e&&(i.Ab(t.wrappingClass),i.yb(1),i.pc("name",t.cancelText),i.yb(1),i.pc("ngIf",t.showSubmit))},directives:[c.a,a.r,o.a],styles:[""]}),e})()},"6B0Y":function(e,t,n){!function(e){"use strict";var t={1:"\u17e1",2:"\u17e2",3:"\u17e3",4:"\u17e4",5:"\u17e5",6:"\u17e6",7:"\u17e7",8:"\u17e8",9:"\u17e9",0:"\u17e0"},n={"\u17e1":"1","\u17e2":"2","\u17e3":"3","\u17e4":"4","\u17e5":"5","\u17e6":"6","\u17e7":"7","\u17e8":"8","\u17e9":"9","\u17e0":"0"};e.defineLocale("km",{months:"\u1798\u1780\u179a\u17b6_\u1780\u17bb\u1798\u17d2\u1797\u17c8_\u1798\u17b8\u1793\u17b6_\u1798\u17c1\u179f\u17b6_\u17a7\u179f\u1797\u17b6_\u1798\u17b7\u1790\u17bb\u1793\u17b6_\u1780\u1780\u17d2\u1780\u178a\u17b6_\u179f\u17b8\u17a0\u17b6_\u1780\u1789\u17d2\u1789\u17b6_\u178f\u17bb\u179b\u17b6_\u179c\u17b7\u1785\u17d2\u1786\u17b7\u1780\u17b6_\u1792\u17d2\u1793\u17bc".split("_"),monthsShort:"\u1798\u1780\u179a\u17b6_\u1780\u17bb\u1798\u17d2\u1797\u17c8_\u1798\u17b8\u1793\u17b6_\u1798\u17c1\u179f\u17b6_\u17a7\u179f\u1797\u17b6_\u1798\u17b7\u1790\u17bb\u1793\u17b6_\u1780\u1780\u17d2\u1780\u178a\u17b6_\u179f\u17b8\u17a0\u17b6_\u1780\u1789\u17d2\u1789\u17b6_\u178f\u17bb\u179b\u17b6_\u179c\u17b7\u1785\u17d2\u1786\u17b7\u1780\u17b6_\u1792\u17d2\u1793\u17bc".split("_"),weekdays:"\u17a2\u17b6\u1791\u17b7\u178f\u17d2\u1799_\u1785\u17d0\u1793\u17d2\u1791_\u17a2\u1784\u17d2\u1782\u17b6\u179a_\u1796\u17bb\u1792_\u1796\u17d2\u179a\u17a0\u179f\u17d2\u1794\u178f\u17b7\u17cd_\u179f\u17bb\u1780\u17d2\u179a_\u179f\u17c5\u179a\u17cd".split("_"),weekdaysShort:"\u17a2\u17b6_\u1785_\u17a2_\u1796_\u1796\u17d2\u179a_\u179f\u17bb_\u179f".split("_"),weekdaysMin:"\u17a2\u17b6_\u1785_\u17a2_\u1796_\u1796\u17d2\u179a_\u179f\u17bb_\u179f".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/\u1796\u17d2\u179a\u17b9\u1780|\u179b\u17d2\u1784\u17b6\u1785/,isPM:function(e){return"\u179b\u17d2\u1784\u17b6\u1785"===e},meridiem:function(e,t,n){return e<12?"\u1796\u17d2\u179a\u17b9\u1780":"\u179b\u17d2\u1784\u17b6\u1785"},calendar:{sameDay:"[\u1790\u17d2\u1784\u17c3\u1793\u17c1\u17c7 \u1798\u17c9\u17c4\u1784] LT",nextDay:"[\u179f\u17d2\u17a2\u17c2\u1780 \u1798\u17c9\u17c4\u1784] LT",nextWeek:"dddd [\u1798\u17c9\u17c4\u1784] LT",lastDay:"[\u1798\u17d2\u179f\u17b7\u179b\u1798\u17b7\u1789 \u1798\u17c9\u17c4\u1784] LT",lastWeek:"dddd [\u179f\u1794\u17d2\u178f\u17b6\u17a0\u17cd\u1798\u17bb\u1793] [\u1798\u17c9\u17c4\u1784] LT",sameElse:"L"},relativeTime:{future:"%s\u1791\u17c0\u178f",past:"%s\u1798\u17bb\u1793",s:"\u1794\u17c9\u17bb\u1793\u17d2\u1798\u17b6\u1793\u179c\u17b7\u1793\u17b6\u1791\u17b8",ss:"%d \u179c\u17b7\u1793\u17b6\u1791\u17b8",m:"\u1798\u17bd\u1799\u1793\u17b6\u1791\u17b8",mm:"%d \u1793\u17b6\u1791\u17b8",h:"\u1798\u17bd\u1799\u1798\u17c9\u17c4\u1784",hh:"%d \u1798\u17c9\u17c4\u1784",d:"\u1798\u17bd\u1799\u1790\u17d2\u1784\u17c3",dd:"%d \u1790\u17d2\u1784\u17c3",M:"\u1798\u17bd\u1799\u1781\u17c2",MM:"%d \u1781\u17c2",y:"\u1798\u17bd\u1799\u1786\u17d2\u1793\u17b6\u17c6",yy:"%d \u1786\u17d2\u1793\u17b6\u17c6"},dayOfMonthOrdinalParse:/\u1791\u17b8\d{1,2}/,ordinal:"\u1791\u17b8%d",preparse:function(e){return e.replace(/[\u17e1\u17e2\u17e3\u17e4\u17e5\u17e6\u17e7\u17e8\u17e9\u17e0]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},week:{dow:1,doy:4}})}(n("wd/R"))},"6JNq":function(e,t,n){var i=n("UTVS"),r=n("Vu81"),s=n("Bs8V"),o=n("m/L8");e.exports=function(e,t){for(var n=r(t),a=o.f,c=s.f,l=0;l{class e{constructor(e){this.docService=e,this.docText="documentation"}ngOnInit(){this.noSubscribe?this.docUrl=this.docService.urlGenerator(this.section):this.docService.subscribeOnce(this.section,e=>{this.docUrl=e})}}return e.\u0275fac=function(t){return new(t||e)(r.Mb(i.a))},e.\u0275cmp=r.Gb({type:e,selectors:[["cd-doc"]],inputs:{section:"section",docText:"docText",noSubscribe:"noSubscribe"},decls:2,vars:2,consts:[["target","_blank",3,"href"]],template:function(e,t){1&e&&(r.Sb(0,"a",0),r.Oc(1),r.Rb()),2&e&&(r.qc("href",t.docUrl,r.Gc),r.yb(1),r.Pc(t.docText))},styles:[""]}),e})()},"7BjC":function(e,t,n){!function(e){"use strict";function t(e,t,n,i){var r={s:["m\xf5ne sekundi","m\xf5ni sekund","paar sekundit"],ss:[e+"sekundi",e+"sekundit"],m:["\xfche minuti","\xfcks minut"],mm:[e+" minuti",e+" minutit"],h:["\xfche tunni","tund aega","\xfcks tund"],hh:[e+" tunni",e+" tundi"],d:["\xfche p\xe4eva","\xfcks p\xe4ev"],M:["kuu aja","kuu aega","\xfcks kuu"],MM:[e+" kuu",e+" kuud"],y:["\xfche aasta","aasta","\xfcks aasta"],yy:[e+" aasta",e+" aastat"]};return t?r[n][2]?r[n][2]:r[n][1]:i?r[n][0]:r[n][1]}e.defineLocale("et",{months:"jaanuar_veebruar_m\xe4rts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_m\xe4rts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"p\xfchap\xe4ev_esmasp\xe4ev_teisip\xe4ev_kolmap\xe4ev_neljap\xe4ev_reede_laup\xe4ev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[T\xe4na,] LT",nextDay:"[Homme,] LT",nextWeek:"[J\xe4rgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s p\xe4rast",past:"%s tagasi",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:"%d p\xe4eva",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},"7C5Q":function(e,t,n){!function(e){"use strict";e.defineLocale("en-in",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:0,doy:6}})}(n("wd/R"))},"7aV9":function(e,t,n){!function(e){"use strict";e.defineLocale("si",{months:"\u0da2\u0db1\u0dc0\u0dcf\u0dbb\u0dd2_\u0db4\u0dd9\u0db6\u0dbb\u0dc0\u0dcf\u0dbb\u0dd2_\u0db8\u0dcf\u0dbb\u0dca\u0dad\u0dd4_\u0d85\u0db4\u0dca\u200d\u0dbb\u0dda\u0dbd\u0dca_\u0db8\u0dd0\u0dba\u0dd2_\u0da2\u0dd6\u0db1\u0dd2_\u0da2\u0dd6\u0dbd\u0dd2_\u0d85\u0d9c\u0ddd\u0dc3\u0dca\u0dad\u0dd4_\u0dc3\u0dd0\u0db4\u0dca\u0dad\u0dd0\u0db8\u0dca\u0db6\u0dbb\u0dca_\u0d94\u0d9a\u0dca\u0dad\u0ddd\u0db6\u0dbb\u0dca_\u0db1\u0ddc\u0dc0\u0dd0\u0db8\u0dca\u0db6\u0dbb\u0dca_\u0daf\u0dd9\u0dc3\u0dd0\u0db8\u0dca\u0db6\u0dbb\u0dca".split("_"),monthsShort:"\u0da2\u0db1_\u0db4\u0dd9\u0db6_\u0db8\u0dcf\u0dbb\u0dca_\u0d85\u0db4\u0dca_\u0db8\u0dd0\u0dba\u0dd2_\u0da2\u0dd6\u0db1\u0dd2_\u0da2\u0dd6\u0dbd\u0dd2_\u0d85\u0d9c\u0ddd_\u0dc3\u0dd0\u0db4\u0dca_\u0d94\u0d9a\u0dca_\u0db1\u0ddc\u0dc0\u0dd0_\u0daf\u0dd9\u0dc3\u0dd0".split("_"),weekdays:"\u0d89\u0dbb\u0dd2\u0daf\u0dcf_\u0dc3\u0db3\u0dd4\u0daf\u0dcf_\u0d85\u0d9f\u0dc4\u0dbb\u0dd4\u0dc0\u0dcf\u0daf\u0dcf_\u0db6\u0daf\u0dcf\u0daf\u0dcf_\u0db6\u0dca\u200d\u0dbb\u0dc4\u0dc3\u0dca\u0db4\u0dad\u0dd2\u0db1\u0dca\u0daf\u0dcf_\u0dc3\u0dd2\u0d9a\u0dd4\u0dbb\u0dcf\u0daf\u0dcf_\u0dc3\u0dd9\u0db1\u0dc3\u0dd4\u0dbb\u0dcf\u0daf\u0dcf".split("_"),weekdaysShort:"\u0d89\u0dbb\u0dd2_\u0dc3\u0db3\u0dd4_\u0d85\u0d9f_\u0db6\u0daf\u0dcf_\u0db6\u0dca\u200d\u0dbb\u0dc4_\u0dc3\u0dd2\u0d9a\u0dd4_\u0dc3\u0dd9\u0db1".split("_"),weekdaysMin:"\u0d89_\u0dc3_\u0d85_\u0db6_\u0db6\u0dca\u200d\u0dbb_\u0dc3\u0dd2_\u0dc3\u0dd9".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [\u0dc0\u0dd0\u0db1\u0dd2] dddd, a h:mm:ss"},calendar:{sameDay:"[\u0d85\u0daf] LT[\u0da7]",nextDay:"[\u0dc4\u0dd9\u0da7] LT[\u0da7]",nextWeek:"dddd LT[\u0da7]",lastDay:"[\u0d8a\u0dba\u0dda] LT[\u0da7]",lastWeek:"[\u0db4\u0dc3\u0dd4\u0d9c\u0dd2\u0dba] dddd LT[\u0da7]",sameElse:"L"},relativeTime:{future:"%s\u0d9a\u0dd2\u0db1\u0dca",past:"%s\u0d9a\u0da7 \u0db4\u0dd9\u0dbb",s:"\u0dad\u0dad\u0dca\u0db4\u0dbb \u0d9a\u0dd2\u0dc4\u0dd2\u0db4\u0dba",ss:"\u0dad\u0dad\u0dca\u0db4\u0dbb %d",m:"\u0db8\u0dd2\u0db1\u0dd2\u0dad\u0dca\u0dad\u0dd4\u0dc0",mm:"\u0db8\u0dd2\u0db1\u0dd2\u0dad\u0dca\u0dad\u0dd4 %d",h:"\u0db4\u0dd0\u0dba",hh:"\u0db4\u0dd0\u0dba %d",d:"\u0daf\u0dd2\u0db1\u0dba",dd:"\u0daf\u0dd2\u0db1 %d",M:"\u0db8\u0dcf\u0dc3\u0dba",MM:"\u0db8\u0dcf\u0dc3 %d",y:"\u0dc0\u0dc3\u0dbb",yy:"\u0dc0\u0dc3\u0dbb %d"},dayOfMonthOrdinalParse:/\d{1,2} \u0dc0\u0dd0\u0db1\u0dd2/,ordinal:function(e){return e+" \u0dc0\u0dd0\u0db1\u0dd2"},meridiemParse:/\u0db4\u0dd9\u0dbb \u0dc0\u0dbb\u0dd4|\u0db4\u0dc3\u0dca \u0dc0\u0dbb\u0dd4|\u0db4\u0dd9.\u0dc0|\u0db4.\u0dc0./,isPM:function(e){return"\u0db4.\u0dc0."===e||"\u0db4\u0dc3\u0dca \u0dc0\u0dbb\u0dd4"===e},meridiem:function(e,t,n){return e>11?n?"\u0db4.\u0dc0.":"\u0db4\u0dc3\u0dca \u0dc0\u0dbb\u0dd4":n?"\u0db4\u0dd9.\u0dc0.":"\u0db4\u0dd9\u0dbb \u0dc0\u0dbb\u0dd4"}})}(n("wd/R"))},"7gMY":function(e,t,n){"use strict";var i=n("9f76"),r=n("/1FC"),s=n("WOAq"),o=n("cSlR"),a=n("oYcn"),c=Object.prototype.hasOwnProperty;t.a=function(e,t){var n=Object(r.a)(e),l=!n&&Object(i.a)(e),u=!n&&!l&&Object(s.a)(e),d=!n&&!l&&!u&&Object(a.a)(e),h=n||l||u||d,f=h?function(e,t){for(var n=-1,i=Array(e);++nthis._complete.call(this._context);a.a.useDeprecatedSynchronousErrorHandling&&e.syncErrorThrowable?(this.__tryOrSetError(e,t),this.unsubscribe()):(this.__tryOrUnsub(t),this.unsubscribe())}else this.unsubscribe()}}__tryOrUnsub(e,t){try{e.call(this._context,t)}catch(n){if(this.unsubscribe(),a.a.useDeprecatedSynchronousErrorHandling)throw n;Object(c.a)(n)}}__tryOrSetError(e,t,n){if(!a.a.useDeprecatedSynchronousErrorHandling)throw new Error("bad call");try{t.call(this._context,n)}catch(i){return a.a.useDeprecatedSynchronousErrorHandling?(e.syncErrorValue=i,e.syncErrorThrown=!0,!0):(Object(c.a)(i),!0)}return!1}_unsubscribe(){const{_parentSubscriber:e}=this;this._context=null,this._parentSubscriber=null,e.unsubscribe()}}},"8/+R":function(e,t,n){!function(e){"use strict";var t={1:"\u0a67",2:"\u0a68",3:"\u0a69",4:"\u0a6a",5:"\u0a6b",6:"\u0a6c",7:"\u0a6d",8:"\u0a6e",9:"\u0a6f",0:"\u0a66"},n={"\u0a67":"1","\u0a68":"2","\u0a69":"3","\u0a6a":"4","\u0a6b":"5","\u0a6c":"6","\u0a6d":"7","\u0a6e":"8","\u0a6f":"9","\u0a66":"0"};e.defineLocale("pa-in",{months:"\u0a1c\u0a28\u0a35\u0a30\u0a40_\u0a2b\u0a3c\u0a30\u0a35\u0a30\u0a40_\u0a2e\u0a3e\u0a30\u0a1a_\u0a05\u0a2a\u0a4d\u0a30\u0a48\u0a32_\u0a2e\u0a08_\u0a1c\u0a42\u0a28_\u0a1c\u0a41\u0a32\u0a3e\u0a08_\u0a05\u0a17\u0a38\u0a24_\u0a38\u0a24\u0a70\u0a2c\u0a30_\u0a05\u0a15\u0a24\u0a42\u0a2c\u0a30_\u0a28\u0a35\u0a70\u0a2c\u0a30_\u0a26\u0a38\u0a70\u0a2c\u0a30".split("_"),monthsShort:"\u0a1c\u0a28\u0a35\u0a30\u0a40_\u0a2b\u0a3c\u0a30\u0a35\u0a30\u0a40_\u0a2e\u0a3e\u0a30\u0a1a_\u0a05\u0a2a\u0a4d\u0a30\u0a48\u0a32_\u0a2e\u0a08_\u0a1c\u0a42\u0a28_\u0a1c\u0a41\u0a32\u0a3e\u0a08_\u0a05\u0a17\u0a38\u0a24_\u0a38\u0a24\u0a70\u0a2c\u0a30_\u0a05\u0a15\u0a24\u0a42\u0a2c\u0a30_\u0a28\u0a35\u0a70\u0a2c\u0a30_\u0a26\u0a38\u0a70\u0a2c\u0a30".split("_"),weekdays:"\u0a10\u0a24\u0a35\u0a3e\u0a30_\u0a38\u0a4b\u0a2e\u0a35\u0a3e\u0a30_\u0a2e\u0a70\u0a17\u0a32\u0a35\u0a3e\u0a30_\u0a2c\u0a41\u0a27\u0a35\u0a3e\u0a30_\u0a35\u0a40\u0a30\u0a35\u0a3e\u0a30_\u0a38\u0a3c\u0a41\u0a71\u0a15\u0a30\u0a35\u0a3e\u0a30_\u0a38\u0a3c\u0a28\u0a40\u0a1a\u0a30\u0a35\u0a3e\u0a30".split("_"),weekdaysShort:"\u0a10\u0a24_\u0a38\u0a4b\u0a2e_\u0a2e\u0a70\u0a17\u0a32_\u0a2c\u0a41\u0a27_\u0a35\u0a40\u0a30_\u0a38\u0a3c\u0a41\u0a15\u0a30_\u0a38\u0a3c\u0a28\u0a40".split("_"),weekdaysMin:"\u0a10\u0a24_\u0a38\u0a4b\u0a2e_\u0a2e\u0a70\u0a17\u0a32_\u0a2c\u0a41\u0a27_\u0a35\u0a40\u0a30_\u0a38\u0a3c\u0a41\u0a15\u0a30_\u0a38\u0a3c\u0a28\u0a40".split("_"),longDateFormat:{LT:"A h:mm \u0a35\u0a1c\u0a47",LTS:"A h:mm:ss \u0a35\u0a1c\u0a47",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm \u0a35\u0a1c\u0a47",LLLL:"dddd, D MMMM YYYY, A h:mm \u0a35\u0a1c\u0a47"},calendar:{sameDay:"[\u0a05\u0a1c] LT",nextDay:"[\u0a15\u0a32] LT",nextWeek:"[\u0a05\u0a17\u0a32\u0a3e] dddd, LT",lastDay:"[\u0a15\u0a32] LT",lastWeek:"[\u0a2a\u0a3f\u0a1b\u0a32\u0a47] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0a35\u0a3f\u0a71\u0a1a",past:"%s \u0a2a\u0a3f\u0a1b\u0a32\u0a47",s:"\u0a15\u0a41\u0a1d \u0a38\u0a15\u0a3f\u0a70\u0a1f",ss:"%d \u0a38\u0a15\u0a3f\u0a70\u0a1f",m:"\u0a07\u0a15 \u0a2e\u0a3f\u0a70\u0a1f",mm:"%d \u0a2e\u0a3f\u0a70\u0a1f",h:"\u0a07\u0a71\u0a15 \u0a18\u0a70\u0a1f\u0a3e",hh:"%d \u0a18\u0a70\u0a1f\u0a47",d:"\u0a07\u0a71\u0a15 \u0a26\u0a3f\u0a28",dd:"%d \u0a26\u0a3f\u0a28",M:"\u0a07\u0a71\u0a15 \u0a2e\u0a39\u0a40\u0a28\u0a3e",MM:"%d \u0a2e\u0a39\u0a40\u0a28\u0a47",y:"\u0a07\u0a71\u0a15 \u0a38\u0a3e\u0a32",yy:"%d \u0a38\u0a3e\u0a32"},preparse:function(e){return e.replace(/[\u0a67\u0a68\u0a69\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0a66]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0a30\u0a3e\u0a24|\u0a38\u0a35\u0a47\u0a30|\u0a26\u0a41\u0a2a\u0a39\u0a3f\u0a30|\u0a38\u0a3c\u0a3e\u0a2e/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0a30\u0a3e\u0a24"===t?e<4?e:e+12:"\u0a38\u0a35\u0a47\u0a30"===t?e:"\u0a26\u0a41\u0a2a\u0a39\u0a3f\u0a30"===t?e>=10?e:e+12:"\u0a38\u0a3c\u0a3e\u0a2e"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"\u0a30\u0a3e\u0a24":e<10?"\u0a38\u0a35\u0a47\u0a30":e<17?"\u0a26\u0a41\u0a2a\u0a39\u0a3f\u0a30":e<20?"\u0a38\u0a3c\u0a3e\u0a2e":"\u0a30\u0a3e\u0a24"},week:{dow:0,doy:6}})}(n("wd/R"))},"85J/":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){const t=/ceph version\s+([^ ]+)\s+\(.+\)/.exec(e);return t?t[1]:e}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"cephShortVersion",type:e,pure:!0}),e})()},"8M4i":function(e,t,n){"use strict";var i=n("ylTp"),r=Object.prototype,s=r.hasOwnProperty,o=r.toString,a=i.a?i.a.toStringTag:void 0,c=Object.prototype.toString,l=i.a?i.a.toStringTag:void 0;t.a=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":l&&l in Object(e)?function(e){var t=s.call(e,a),n=e[a];try{e[a]=void 0;var i=!0}catch(c){}var r=o.call(e);return i&&(t?e[a]=n:delete e[a]),r}(e):function(e){return c.call(e)}(e)}},"8Y7J":function(e,t,n){"use strict";n.d(t,"a",(function(){return Is})),n.d(t,"b",(function(){return eu})),n.d(t,"c",(function(){return Jl})),n.d(t,"d",(function(){return ql})),n.d(t,"e",(function(){return Gl})),n.d(t,"f",(function(){return Vu})),n.d(t,"g",(function(){return Iu})),n.d(t,"h",(function(){return bs})),n.d(t,"i",(function(){return du})),n.d(t,"j",(function(){return _a})),n.d(t,"k",(function(){return ma})),n.d(t,"l",(function(){return iu})),n.d(t,"m",(function(){return ya})),n.d(t,"n",(function(){return En})),n.d(t,"o",(function(){return Ml})),n.d(t,"p",(function(){return q})),n.d(t,"q",(function(){return d})),n.d(t,"r",(function(){return U})),n.d(t,"s",(function(){return As})),n.d(t,"t",(function(){return Fa})),n.d(t,"u",(function(){return Ya})),n.d(t,"v",(function(){return nu})),n.d(t,"w",(function(){return ce})),n.d(t,"x",(function(){return ju})),n.d(t,"y",(function(){return ae})),n.d(t,"z",(function(){return Ou})),n.d(t,"A",(function(){return pu})),n.d(t,"B",(function(){return h})),n.d(t,"C",(function(){return Xl})),n.d(t,"D",(function(){return Zl})),n.d(t,"E",(function(){return Ma})),n.d(t,"F",(function(){return wa})),n.d(t,"G",(function(){return Sa})),n.d(t,"H",(function(){return ka})),n.d(t,"I",(function(){return Si})),n.d(t,"J",(function(){return p})),n.d(t,"K",(function(){return Yu})),n.d(t,"L",(function(){return Wa})),n.d(t,"M",(function(){return Su})),n.d(t,"N",(function(){return _s})),n.d(t,"O",(function(){return Da})),n.d(t,"P",(function(){return Ba})),n.d(t,"Q",(function(){return _e})),n.d(t,"R",(function(){return Lu})),n.d(t,"S",(function(){return Qn})),n.d(t,"T",(function(){return R})),n.d(t,"U",(function(){return Jn})),n.d(t,"V",(function(){return Hu})),n.d(t,"W",(function(){return ku})),n.d(t,"X",(function(){return tu})),n.d(t,"Y",(function(){return ys})),n.d(t,"Z",(function(){return ac})),n.d(t,"ab",(function(){return vi})),n.d(t,"bb",(function(){return ni})),n.d(t,"cb",(function(){return zn})),n.d(t,"db",(function(){return Hn})),n.d(t,"eb",(function(){return Un})),n.d(t,"fb",(function(){return Vn})),n.d(t,"gb",(function(){return Wn})),n.d(t,"hb",(function(){return Bn})),n.d(t,"ib",(function(){return ic})),n.d(t,"jb",(function(){return $u})),n.d(t,"kb",(function(){return rc})),n.d(t,"lb",(function(){return sc})),n.d(t,"mb",(function(){return $n})),n.d(t,"nb",(function(){return F})),n.d(t,"ob",(function(){return Bs})),n.d(t,"pb",(function(){return go})),n.d(t,"qb",(function(){return bo})),n.d(t,"rb",(function(){return nc})),n.d(t,"sb",(function(){return Qe})),n.d(t,"tb",(function(){return C})),n.d(t,"ub",(function(){return Yn})),n.d(t,"vb",(function(){return Ns})),n.d(t,"wb",(function(){return Ve})),n.d(t,"xb",(function(){return pa})),n.d(t,"yb",(function(){return Bi})),n.d(t,"zb",(function(){return Xs})),n.d(t,"Ab",(function(){return Yo})),n.d(t,"Bb",(function(){return na})),n.d(t,"Cb",(function(){return ia})),n.d(t,"Db",(function(){return ra})),n.d(t,"Eb",(function(){return Fo})),n.d(t,"Fb",(function(){return Fl})),n.d(t,"Gb",(function(){return Se})),n.d(t,"Hb",(function(){return Oe})),n.d(t,"Ib",(function(){return _})),n.d(t,"Jb",(function(){return y})),n.d(t,"Kb",(function(){return De})),n.d(t,"Lb",(function(){return Le})),n.d(t,"Mb",(function(){return ro})),n.d(t,"Nb",(function(){return uo})),n.d(t,"Ob",(function(){return po})),n.d(t,"Pb",(function(){return fo})),n.d(t,"Qb",(function(){return ho})),n.d(t,"Rb",(function(){return lo})),n.d(t,"Sb",(function(){return co})),n.d(t,"Tb",(function(){return mo})),n.d(t,"Ub",(function(){return Cn})),n.d(t,"Vb",(function(){return sa})),n.d(t,"Wb",(function(){return Xc})),n.d(t,"Xb",(function(){return nl})),n.d(t,"Yb",(function(){return el})),n.d(t,"Zb",(function(){return Zc})),n.d(t,"ac",(function(){return tl})),n.d(t,"bc",(function(){return il})),n.d(t,"cc",(function(){return Kc})),n.d(t,"dc",(function(){return ie})),n.d(t,"ec",(function(){return so})),n.d(t,"fc",(function(){return Ul})),n.d(t,"gc",(function(){return _o})),n.d(t,"hc",(function(){return $l})),n.d(t,"ic",(function(){return wo})),n.d(t,"jc",(function(){return gl})),n.d(t,"kc",(function(){return _l})),n.d(t,"lc",(function(){return yl})),n.d(t,"mc",(function(){return vl})),n.d(t,"nc",(function(){return Do})),n.d(t,"oc",(function(){return Mo})),n.d(t,"pc",(function(){return oo})),n.d(t,"qc",(function(){return To})),n.d(t,"rc",(function(){return Co})),n.d(t,"sc",(function(){return Oo})),n.d(t,"tc",(function(){return al})),n.d(t,"uc",(function(){return cl})),n.d(t,"vc",(function(){return ll})),n.d(t,"wc",(function(){return ul})),n.d(t,"xc",(function(){return dl})),n.d(t,"yc",(function(){return hl})),n.d(t,"zc",(function(){return Il})),n.d(t,"Ac",(function(){return io})),n.d(t,"Bc",(function(){return ln})),n.d(t,"Cc",(function(){return cn})),n.d(t,"Dc",(function(){return bt})),n.d(t,"Ec",(function(){return Mi})),n.d(t,"Fc",(function(){return ki})),n.d(t,"Gc",(function(){return xi})),n.d(t,"Hc",(function(){return Te})),n.d(t,"Ic",(function(){return Yl})),n.d(t,"Jc",(function(){return Pl})),n.d(t,"Kc",(function(){return No})),n.d(t,"Lc",(function(){return oa})),n.d(t,"Mc",(function(){return no})),n.d(t,"Nc",(function(){return Bl})),n.d(t,"Oc",(function(){return Ko})),n.d(t,"Pc",(function(){return Zo})),n.d(t,"Qc",(function(){return Xo})),n.d(t,"Rc",(function(){return ea})),n.d(t,"Sc",(function(){return ta})),n.d(t,"Tc",(function(){return jl}));var i=n("XNiG"),r=n("quSY"),s=n("HDdC"),o=n("VRyK"),a=n("w1tV");function c(e){return{toString:e}.toString()}const l="__parameters__";function u(e,t,n){return c(()=>{const i=function(e){return function(...t){if(e){const n=e(...t);for(const e in n)this[e]=n[e]}}}(t);function r(...e){if(this instanceof r)return i.apply(this,e),this;const t=new r(...e);return n.annotation=t,n;function n(e,n,i){const r=e.hasOwnProperty(l)?e[l]:Object.defineProperty(e,l,{value:[]})[l];for(;r.length<=i;)r.push(null);return(r[i]=r[i]||[]).push(t),e}}return n&&(r.prototype=Object.create(n.prototype)),r.prototype.ngMetadataName=e,r.annotationCls=r,r})}const d=u("Inject",e=>({token:e})),h=u("Optional"),f=u("Self"),p=u("SkipSelf");var m=function(e){return e[e.Default=0]="Default",e[e.Host=1]="Host",e[e.Self=2]="Self",e[e.SkipSelf=4]="SkipSelf",e[e.Optional=8]="Optional",e}({});function b(e){for(let t in e)if(e[t]===b)return t;throw Error("Could not find renamed property on target object.")}function g(e,t){for(const n in t)t.hasOwnProperty(n)&&!e.hasOwnProperty(n)&&(e[n]=t[n])}function _(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function y(e){return{factory:e.factory,providers:e.providers||[],imports:e.imports||[]}}function v(e){return w(e,e[M])||w(e,e[D])}function w(e,t){return t&&t.token===e?t:null}function S(e){return e&&(e.hasOwnProperty(x)||e.hasOwnProperty(T))?e[x]:null}const M=b({"\u0275prov":b}),x=b({"\u0275inj":b}),k=b({"\u0275provFallback":b}),D=b({ngInjectableDef:b}),T=b({ngInjectorDef:b});function C(e){if("string"==typeof e)return e;if(Array.isArray(e))return"["+e.map(C).join(", ")+"]";if(null==e)return""+e;if(e.overriddenName)return""+e.overriddenName;if(e.name)return""+e.name;const t=e.toString();if(null==t)return""+t;const n=t.indexOf("\n");return-1===n?t:t.substring(0,n)}function O(e,t){return null==e||""===e?null===t?"":t:null==t||""===t?e:e+" "+t}const L=b({__forward_ref__:b});function R(e){return e.__forward_ref__=R,e.toString=function(){return C(this())},e}function E(e){return A(e)?e():e}function A(e){return"function"==typeof e&&e.hasOwnProperty(L)&&e.__forward_ref__===R}const I="undefined"!=typeof globalThis&&globalThis,P="undefined"!=typeof window&&window,j="undefined"!=typeof self&&"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&self,N="undefined"!=typeof global&&global,F=I||N||P||j,Y=b({"\u0275cmp":b}),z=b({"\u0275dir":b}),$=b({"\u0275pipe":b}),H=b({"\u0275mod":b}),W=b({"\u0275loc":b}),V=b({"\u0275fac":b}),B=b({__NG_ELEMENT_ID__:b});class U{constructor(e,t){this._desc=e,this.ngMetadataName="InjectionToken",this.\u0275prov=void 0,"number"==typeof t?this.__NG_ELEMENT_ID__=t:void 0!==t&&(this.\u0275prov=_({token:this,providedIn:t.providedIn||"root",factory:t.factory}))}toString(){return"InjectionToken "+this._desc}}const q=new U("INJECTOR",-1),G={},J=/\n/gm,Q="__source",K=b({provide:String,useValue:b});let Z,X=void 0;function ee(e){const t=X;return X=e,t}function te(e){const t=Z;return Z=e,t}function ne(e,t=m.Default){if(void 0===X)throw new Error("inject() must be called from an injection context");return null===X?re(e,void 0,t):X.get(e,t&m.Optional?null:void 0,t)}function ie(e,t=m.Default){return(Z||ne)(E(e),t)}function re(e,t,n){const i=v(e);if(i&&"root"==i.providedIn)return void 0===i.value?i.value=i.factory():i.value;if(n&m.Optional)return null;if(void 0!==t)return t;throw new Error(`Injector: NOT_FOUND [${C(e)}]`)}function se(e){const t=[];for(let n=0;nArray.isArray(e)?ue(e,t):t(e))}function de(e,t,n){t>=e.length?e.push(n):e.splice(t,0,n)}function he(e,t){return t>=e.length-1?e.pop():e.splice(t,1)[0]}function fe(e,t){const n=[];for(let i=0;i=0?e[1|i]=n:(i=~i,function(e,t,n,i){let r=e.length;if(r==t)e.push(n,i);else if(1===r)e.push(i,e[0]),e[0]=n;else{for(r--,e.push(e[r-1],e[r]);r>t;)e[r]=e[r-2],r--;e[t]=n,e[t+1]=i}}(e,i,t,n)),i}function me(e,t){const n=be(e,t);if(n>=0)return e[1|n]}function be(e,t){return function(e,t,n){let i=0,r=e.length>>1;for(;r!==i;){const n=i+(r-i>>1),s=e[n<<1];if(t===s)return n<<1;s>t?r=n:i=n+1}return~(r<<1)}(e,t)}var ge=function(e){return e[e.OnPush=0]="OnPush",e[e.Default=1]="Default",e}({}),_e=function(e){return e[e.Emulated=0]="Emulated",e[e.Native=1]="Native",e[e.None=2]="None",e[e.ShadowDom=3]="ShadowDom",e}({});const ye={},ve=[];let we=0;function Se(e){return c(()=>{const t={},n={type:e.type,providersResolver:null,decls:e.decls,vars:e.vars,factory:null,template:e.template||null,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:t,inputs:null,outputs:null,exportAs:e.exportAs||null,onPush:e.changeDetection===ge.OnPush,directiveDefs:null,pipeDefs:null,selectors:e.selectors||ve,viewQuery:e.viewQuery||null,features:e.features||null,data:e.data||{},encapsulation:e.encapsulation||_e.Emulated,id:"c",styles:e.styles||ve,_:null,setInput:null,schemas:e.schemas||null,tView:null},i=e.directives,r=e.features,s=e.pipes;return n.id+=we++,n.inputs=Ce(e.inputs,t),n.outputs=Ce(e.outputs),r&&r.forEach(e=>e(n)),n.directiveDefs=i?()=>("function"==typeof i?i():i).map(Me):null,n.pipeDefs=s?()=>("function"==typeof s?s():s).map(xe):null,n})}function Me(e){return Re(e)||function(e){return e[z]||null}(e)}function xe(e){return function(e){return e[$]||null}(e)}const ke={};function De(e){const t={type:e.type,bootstrap:e.bootstrap||ve,declarations:e.declarations||ve,imports:e.imports||ve,exports:e.exports||ve,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null};return null!=e.id&&c(()=>{ke[e.id]=e.type}),t}function Te(e,t){return c(()=>{const n=Ae(e,!0);n.declarations=t.declarations||ve,n.imports=t.imports||ve,n.exports=t.exports||ve})}function Ce(e,t){if(null==e)return ye;const n={};for(const i in e)if(e.hasOwnProperty(i)){let r=e[i],s=r;Array.isArray(r)&&(s=r[1],r=r[0]),n[r]=i,t&&(t[r]=s)}return n}const Oe=Se;function Le(e){return{type:e.type,name:e.name,factory:null,pure:!1!==e.pure,onDestroy:e.type.prototype.ngOnDestroy||null}}function Re(e){return e[Y]||null}function Ee(e,t){return e.hasOwnProperty(V)?e[V]:null}function Ae(e,t){const n=e[H]||null;if(!n&&!0===t)throw new Error(`Type ${C(e)} does not have '\u0275mod' property.`);return n}const Ie=20,Pe=10;function je(e){return Array.isArray(e)&&"object"==typeof e[1]}function Ne(e){return Array.isArray(e)&&!0===e[1]}function Fe(e){return 0!=(8&e.flags)}function Ye(e){return 2==(2&e.flags)}function ze(e){return 1==(1&e.flags)}function $e(e){return null!==e.template}function He(e){return 0!=(512&e[2])}class We{constructor(e,t,n){this.previousValue=e,this.currentValue=t,this.firstChange=n}isFirstChange(){return this.firstChange}}function Ve(){return Be}function Be(e){return e.type.prototype.ngOnChanges&&(e.setInput=qe),Ue}function Ue(){const e=Ge(this),t=null==e?void 0:e.current;if(t){const n=e.previous;if(n===ye)e.previous=t;else for(let e in t)n[e]=t[e];e.current=null,this.ngOnChanges(t)}}function qe(e,t,n,i){const r=Ge(e)||function(e,t){return e.__ngSimpleChanges__=t}(e,{previous:ye,current:null}),s=r.current||(r.current={}),o=r.previous,a=this.declaredInputs[n],c=o[a];s[a]=new We(c&&c.currentValue,t,o===ye),e[i]=t}function Ge(e){return e.__ngSimpleChanges__||null}Ve.ngInherit=!0;let Je=void 0;function Qe(e){Je=e}function Ke(){return void 0!==Je?Je:"undefined"!=typeof document?document:void 0}function Ze(e){return!!e.listen}const Xe={createRenderer:(e,t)=>Ke()};function et(e){for(;Array.isArray(e);)e=e[0];return e}function tt(e,t){return et(t[e+Ie])}function nt(e,t){return et(t[e.index])}function it(e,t){return e.data[t+Ie]}function rt(e,t){return e[t+Ie]}function st(e,t){const n=t[e];return je(n)?n:n[0]}function ot(e){const t=function(e){return e.__ngContext__||null}(e);return t?Array.isArray(t)?t:t.lView:null}function at(e){return 4==(4&e[2])}function ct(e){return 128==(128&e[2])}function lt(e,t){return null===e||null==t?null:e[t]}function ut(e){e[18]=0}function dt(e,t){e[5]+=t;let n=e,i=e[3];for(;null!==i&&(1===t&&1===n[5]||-1===t&&0===n[5]);)i[5]+=t,n=i,i=i[3]}const ht={lFrame:Pt(null),bindingsEnabled:!0,checkNoChangesMode:!1};function ft(){return ht.bindingsEnabled}function pt(){return ht.lFrame.lView}function mt(){return ht.lFrame.tView}function bt(e){ht.lFrame.contextLView=e}function gt(){return ht.lFrame.currentTNode}function _t(e,t){ht.lFrame.currentTNode=e,ht.lFrame.isParent=t}function yt(){return ht.lFrame.isParent}function vt(){ht.lFrame.isParent=!1}function wt(){return ht.checkNoChangesMode}function St(e){ht.checkNoChangesMode=e}function Mt(){const e=ht.lFrame;let t=e.bindingRootIndex;return-1===t&&(t=e.bindingRootIndex=e.tView.bindingStartIndex),t}function xt(){return ht.lFrame.bindingIndex}function kt(){return ht.lFrame.bindingIndex++}function Dt(e){const t=ht.lFrame,n=t.bindingIndex;return t.bindingIndex=t.bindingIndex+e,n}function Tt(e,t){const n=ht.lFrame;n.bindingIndex=n.bindingRootIndex=e,Ct(t)}function Ct(e){ht.lFrame.currentDirectiveIndex=e}function Ot(e){const t=ht.lFrame.currentDirectiveIndex;return-1===t?null:e[t]}function Lt(){return ht.lFrame.currentQueryIndex}function Rt(e){ht.lFrame.currentQueryIndex=e}function Et(e,t){const n=It();ht.lFrame=n,n.currentTNode=t,n.lView=e}function At(e){const t=It(),n=e[1];ht.lFrame=t,t.currentTNode=n.firstChild,t.lView=e,t.tView=n,t.contextLView=e,t.bindingIndex=n.bindingStartIndex}function It(){const e=ht.lFrame,t=null===e?null:e.child;return null===t?Pt(e):t}function Pt(e){const t={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:0,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null};return null!==e&&(e.child=t),t}function jt(){const e=ht.lFrame;return ht.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}const Nt=jt;function Ft(){const e=jt();e.isParent=!0,e.tView=null,e.selectedIndex=0,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function Yt(){return ht.lFrame.selectedIndex}function zt(e){ht.lFrame.selectedIndex=e}function $t(){const e=ht.lFrame;return it(e.tView,e.selectedIndex)}function Ht(e,t){for(let n=t.directiveStart,i=t.directiveEnd;n=i)break}else t[o]<0&&(e[18]+=65536),(s>11>16&&(3&e[2])===t&&(e[2]+=2048,s.call(o)):s.call(o)}const Gt=-1;class Jt{constructor(e,t,n){this.factory=e,this.resolving=!1,this.canSeeViewProviders=t,this.injectImpl=n}}function Qt(e,t,n){const i=Ze(e);let r=0;for(;rt){o=s-1;break}}}for(;s>16,i=t;for(;n>0;)i=i[15],n--;return i}function sn(e){return"string"==typeof e?e:null==e?"":""+e}function on(e){return"function"==typeof e?e.name||e.toString():"object"==typeof e&&null!=e&&"function"==typeof e.type?e.type.name||e.type.toString():sn(e)}const an=(()=>("undefined"!=typeof requestAnimationFrame&&requestAnimationFrame||setTimeout).bind(F))();function cn(e){return{name:"window",target:e.ownerDocument.defaultView}}function ln(e){return{name:"body",target:e.ownerDocument.body}}function un(e){return e instanceof Function?e():e}let dn=!0;function hn(e){const t=dn;return dn=e,t}let fn=0;function pn(e,t){const n=bn(e,t);if(-1!==n)return n;const i=t[1];i.firstCreatePass&&(e.injectorIndex=t.length,mn(i.data,e),mn(t,null),mn(i.blueprint,null));const r=gn(e,t),s=e.injectorIndex;if(tn(r)){const e=nn(r),n=rn(r,t),i=n[1].data;for(let r=0;r<8;r++)t[s+r]=n[e+r]|i[e+r]}return t[s+8]=r,s}function mn(e,t){e.push(0,0,0,0,0,0,0,0,t)}function bn(e,t){return-1===e.injectorIndex||e.parent&&e.parent.injectorIndex===e.injectorIndex||null===t[e.injectorIndex+8]?-1:e.injectorIndex}function gn(e,t){if(e.parent&&-1!==e.parent.injectorIndex)return e.parent.injectorIndex;let n=0,i=null,r=t;for(;null!==r;){const e=r[1],t=e.type;if(i=2===t?e.declTNode:1===t?r[6]:null,null===i)return Gt;if(n++,r=r[15],-1!==i.injectorIndex)return i.injectorIndex|n<<16}return Gt}function _n(e,t,n){!function(e,t,n){let i;"string"==typeof n?i=n.charCodeAt(0)||0:n.hasOwnProperty(B)&&(i=n[B]),null==i&&(i=n[B]=fn++);const r=255&i,s=1<0?255&t:t}(n);if("function"==typeof r){Et(t,e);try{const e=r();if(null!=e||i&m.Optional)return e;throw new Error(`No provider for ${on(n)}!`)}finally{Nt()}}else if("number"==typeof r){if(-1===r)return new Dn(e,t);let s=null,o=bn(e,t),a=Gt,c=i&m.Host?t[16][6]:null;for((-1===o||i&m.SkipSelf)&&(a=-1===o?gn(e,t):t[o+8],a!==Gt&&kn(i,!1)?(s=t[1],o=nn(a),t=rn(a,t)):o=-1);-1!==o;){const e=t[1];if(xn(r,o,e.data)){const e=wn(o,t,n,s,i,c);if(e!==vn)return e}a=t[o+8],a!==Gt&&kn(i,t[1].data[o+8]===c)&&xn(r,o,t)?(s=e,o=nn(a),t=rn(a,t)):o=-1}}}if(i&m.Optional&&void 0===r&&(r=null),0==(i&(m.Self|m.Host))){const e=t[9],s=te(void 0);try{return e?e.get(n,r,i&m.Optional):re(n,r,i&m.Optional)}finally{te(s)}}if(i&m.Optional)return r;throw new Error(`NodeInjector: NOT_FOUND [${on(n)}]`)}const vn={};function wn(e,t,n,i,r,s){const o=t[1],a=o.data[e+8],c=Sn(a,o,n,null==i?Ye(a)&&dn:i!=o&&2===a.type,r&m.Host&&s===a);return null!==c?Mn(t,o,c,a):vn}function Sn(e,t,n,i,r){const s=e.providerIndexes,o=t.data,a=1048575&s,c=e.directiveStart,l=s>>20,u=r?a+l:e.directiveEnd;for(let d=i?a:a+l;d=c&&e.type===n)return d}if(r){const e=o[c];if(e&&$e(e)&&e.type===n)return c}return null}function Mn(e,t,n,i){let r=e[n];const s=t.data;if(r instanceof Jt){const o=r;if(o.resolving)throw new Error("Circular dep for "+on(s[n]));const a=hn(o.canSeeViewProviders);o.resolving=!0;const c=o.injectImpl?te(o.injectImpl):null;Et(e,i);try{r=e[n]=o.factory(void 0,s,e,i),t.firstCreatePass&&n>=i.directiveStart&&function(e,t,n){const{ngOnChanges:i,ngOnInit:r,ngDoCheck:s}=t.type.prototype;if(i){const i=Be(t);(n.preOrderHooks||(n.preOrderHooks=[])).push(e,i),(n.preOrderCheckHooks||(n.preOrderCheckHooks=[])).push(e,i)}r&&(n.preOrderHooks||(n.preOrderHooks=[])).push(0-e,r),s&&((n.preOrderHooks||(n.preOrderHooks=[])).push(e,s),(n.preOrderCheckHooks||(n.preOrderCheckHooks=[])).push(e,s))}(n,s[n],t)}finally{null!==c&&te(c),hn(a),o.resolving=!1,Nt()}}return r}function xn(e,t,n){const i=64&e,r=32&e;let s;return s=128&e?i?r?n[t+7]:n[t+6]:r?n[t+5]:n[t+4]:i?r?n[t+3]:n[t+2]:r?n[t+1]:n[t],!!(s&1<{const e=Tn(E(t));return e?e():null};let n=Ee(t);if(null===n){const e=S(t);n=e&&e.factory}return n||null}function Cn(e){return c(()=>{const t=e.prototype.constructor,n=t[V]||Tn(t),i=Object.prototype;let r=Object.getPrototypeOf(e.prototype).constructor;for(;r&&r!==i;){const e=r[V]||Tn(r);if(e&&e!==n)return e;r=Object.getPrototypeOf(r)}return e=>new e})}function On(e){return e.ngDebugContext}function Ln(e){return e.ngOriginalError}function Rn(e,...t){e.error(...t)}class En{constructor(){this._console=console}handleError(e){const t=this._findOriginalError(e),n=this._findContext(e),i=function(e){return e.ngErrorLogger||Rn}(e);i(this._console,"ERROR",e),t&&i(this._console,"ORIGINAL ERROR",t),n&&i(this._console,"ERROR CONTEXT",n)}_findContext(e){return e?On(e)?On(e):this._findContext(Ln(e)):null}_findOriginalError(e){let t=Ln(e);for(;t&&Ln(t);)t=Ln(t);return t}}class An{constructor(e){this.changingThisBreaksApplicationSecurity=e}toString(){return"SafeValue must use [property]=binding: "+this.changingThisBreaksApplicationSecurity+" (see http://g.co/ng/security#xss)"}}class In extends An{getTypeName(){return"HTML"}}class Pn extends An{getTypeName(){return"Style"}}class jn extends An{getTypeName(){return"Script"}}class Nn extends An{getTypeName(){return"URL"}}class Fn extends An{getTypeName(){return"ResourceURL"}}function Yn(e){return e instanceof An?e.changingThisBreaksApplicationSecurity:e}function zn(e,t){const n=$n(e);if(null!=n&&n!==t){if("ResourceURL"===n&&"URL"===t)return!0;throw new Error(`Required a safe ${t}, got a ${n} (see http://g.co/ng/security#xss)`)}return n===t}function $n(e){return e instanceof An&&e.getTypeName()||null}function Hn(e){return new In(e)}function Wn(e){return new Pn(e)}function Vn(e){return new jn(e)}function Bn(e){return new Nn(e)}function Un(e){return new Fn(e)}let qn=!0,Gn=!1;function Jn(){return Gn=!0,qn}function Qn(){if(Gn)throw new Error("Cannot enable prod mode after platform setup.");qn=!1}function Kn(e){return function(){try{return!!(new window.DOMParser).parseFromString("","text/html")}catch(e){return!1}}()?new Zn:new Xn(e)}class Zn{getInertBodyElement(e){e=""+e;try{const t=(new window.DOMParser).parseFromString(e,"text/html").body;return t.removeChild(t.firstChild),t}catch(t){return null}}}class Xn{constructor(e){if(this.defaultDoc=e,this.inertDocument=this.defaultDoc.implementation.createHTMLDocument("sanitization-inert"),null==this.inertDocument.body){const e=this.inertDocument.createElement("html");this.inertDocument.appendChild(e);const t=this.inertDocument.createElement("body");e.appendChild(t)}}getInertBodyElement(e){const t=this.inertDocument.createElement("template");if("content"in t)return t.innerHTML=e,t;const n=this.inertDocument.createElement("body");return n.innerHTML=e,this.defaultDoc.documentMode&&this.stripCustomNsAttrs(n),n}stripCustomNsAttrs(e){const t=e.attributes;for(let i=t.length-1;0ni(e.trim())).join(", ")}function ri(e){const t={};for(const n of e.split(","))t[n]=!0;return t}function si(...e){const t={};for(const n of e)for(const e in n)n.hasOwnProperty(e)&&(t[e]=!0);return t}const oi=ri("area,br,col,hr,img,wbr"),ai=ri("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),ci=ri("rp,rt"),li=si(ci,ai),ui=si(oi,si(ai,ri("address,article,aside,blockquote,caption,center,del,details,dialog,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,main,map,menu,nav,ol,pre,section,summary,table,ul")),si(ci,ri("a,abbr,acronym,audio,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,picture,q,ruby,rp,rt,s,samp,small,source,span,strike,strong,sub,sup,time,track,tt,u,var,video")),li),di=ri("background,cite,href,itemtype,longdesc,poster,src,xlink:href"),hi=ri("srcset"),fi=si(di,hi,ri("abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,controls,coords,datetime,default,dir,download,face,headers,height,hidden,hreflang,hspace,ismap,itemscope,itemprop,kind,label,lang,language,loop,media,muted,nohref,nowrap,open,preload,rel,rev,role,rows,rowspan,rules,scope,scrolling,shape,size,sizes,span,srclang,start,summary,tabindex,target,title,translate,type,usemap,valign,value,vspace,width"),ri("aria-activedescendant,aria-atomic,aria-autocomplete,aria-busy,aria-checked,aria-colcount,aria-colindex,aria-colspan,aria-controls,aria-current,aria-describedby,aria-details,aria-disabled,aria-dropeffect,aria-errormessage,aria-expanded,aria-flowto,aria-grabbed,aria-haspopup,aria-hidden,aria-invalid,aria-keyshortcuts,aria-label,aria-labelledby,aria-level,aria-live,aria-modal,aria-multiline,aria-multiselectable,aria-orientation,aria-owns,aria-placeholder,aria-posinset,aria-pressed,aria-readonly,aria-relevant,aria-required,aria-roledescription,aria-rowcount,aria-rowindex,aria-rowspan,aria-selected,aria-setsize,aria-sort,aria-valuemax,aria-valuemin,aria-valuenow,aria-valuetext")),pi=ri("script,style,template");class mi{constructor(){this.sanitizedSomething=!1,this.buf=[]}sanitizeChildren(e){let t=e.firstChild,n=!0;for(;t;)if(t.nodeType===Node.ELEMENT_NODE?n=this.startElement(t):t.nodeType===Node.TEXT_NODE?this.chars(t.nodeValue):this.sanitizedSomething=!0,n&&t.firstChild)t=t.firstChild;else for(;t;){t.nodeType===Node.ELEMENT_NODE&&this.endElement(t);let e=this.checkClobberedElement(t,t.nextSibling);if(e){t=e;break}t=this.checkClobberedElement(t,t.parentNode)}return this.buf.join("")}startElement(e){const t=e.nodeName.toLowerCase();if(!ui.hasOwnProperty(t))return this.sanitizedSomething=!0,!pi.hasOwnProperty(t);this.buf.push("<"),this.buf.push(t);const n=e.attributes;for(let i=0;i"),!0}endElement(e){const t=e.nodeName.toLowerCase();ui.hasOwnProperty(t)&&!oi.hasOwnProperty(t)&&(this.buf.push(""))}chars(e){this.buf.push(_i(e))}checkClobberedElement(e,t){if(t&&(e.compareDocumentPosition(t)&Node.DOCUMENT_POSITION_CONTAINED_BY)===Node.DOCUMENT_POSITION_CONTAINED_BY)throw new Error("Failed to sanitize html because the element is clobbered: "+e.outerHTML);return t}}const bi=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,gi=/([^\#-~ |!])/g;function _i(e){return e.replace(/&/g,"&").replace(bi,(function(e){return"&#"+(1024*(e.charCodeAt(0)-55296)+(e.charCodeAt(1)-56320)+65536)+";"})).replace(gi,(function(e){return"&#"+e.charCodeAt(0)+";"})).replace(//g,">")}let yi;function vi(e,t){let n=null;try{yi=yi||Kn(e);let i=t?String(t):"";n=yi.getInertBodyElement(i);let r=5,s=i;do{if(0===r)throw new Error("Failed to sanitize html because the input is unstable");r--,i=s,s=n.innerHTML,n=yi.getInertBodyElement(i)}while(i!==s);const o=new mi,a=o.sanitizeChildren(wi(n)||n);return Jn()&&o.sanitizedSomething&&console.warn("WARNING: sanitizing HTML stripped some content, see http://g.co/ng/security#xss"),a}finally{if(n){const e=wi(n)||n;for(;e.firstChild;)e.removeChild(e.firstChild)}}}function wi(e){return"content"in e&&function(e){return e.nodeType===Node.ELEMENT_NODE&&"TEMPLATE"===e.nodeName}(e)?e.content:null}var Si=function(e){return e[e.NONE=0]="NONE",e[e.HTML=1]="HTML",e[e.STYLE=2]="STYLE",e[e.SCRIPT=3]="SCRIPT",e[e.URL=4]="URL",e[e.RESOURCE_URL=5]="RESOURCE_URL",e}({});function Mi(e){const t=Di();return t?t.sanitize(Si.HTML,e)||"":zn(e,"HTML")?Yn(e):vi(Ke(),sn(e))}function xi(e){const t=Di();return t?t.sanitize(Si.URL,e)||"":zn(e,"URL")?Yn(e):ni(sn(e))}function ki(e){const t=Di();if(t)return t.sanitize(Si.RESOURCE_URL,e)||"";if(zn(e,"ResourceURL"))return Yn(e);throw new Error("unsafe value used in a resource URL context (see http://g.co/ng/security#xss)")}function Di(){const e=pt();return e&&e[12]}function Ti(e,t){e.__ngContext__=t}function Ci(e,t,n){let i=e.length;for(;;){const r=e.indexOf(t,n);if(-1===r)return r;if(0===r||e.charCodeAt(r-1)<=32){const n=t.length;if(r+n===i||e.charCodeAt(r+n)<=32)return r}n=r+1}}const Oi="ng-template";function Li(e,t,n){let i=0;for(;is?"":r[u+1].toLowerCase();const t=8&i?e:null;if(t&&-1!==Ci(t,l,0)||2&i&&l!==e){if(Ii(i))return!1;o=!0}}}}else{if(!o&&!Ii(i)&&!Ii(c))return!1;if(o&&Ii(c))continue;o=!1,i=c|1&i}}return Ii(i)||o}function Ii(e){return 0==(1&e)}function Pi(e,t,n,i){if(null===t)return-1;let r=0;if(i||!n){let n=!1;for(;r-1)for(n++;n0?'="'+t+'"':"")+"]"}else 8&i?r+="."+o:4&i&&(r+=" "+o);else""===r||Ii(o)||(t+=Fi(s,r),r=""),i=o,s=s||!Ii(i);n++}return""!==r&&(t+=Fi(s,r)),t}const zi={};function $i(e){const t=e[3];return Ne(t)?t[3]:t}function Hi(e){return Vi(e[13])}function Wi(e){return Vi(e[4])}function Vi(e){for(;null!==e&&!Ne(e);)e=e[4];return e}function Bi(e){Ui(mt(),pt(),Yt()+e,wt())}function Ui(e,t,n,i){if(!i)if(3==(3&t[2])){const i=e.preOrderCheckHooks;null!==i&&Wt(t,i,n)}else{const i=e.preOrderHooks;null!==i&&Vt(t,i,0,n)}zt(n)}function qi(e,t){return e<<17|t<<2}function Gi(e){return e>>17&32767}function Ji(e){return 2|e}function Qi(e){return(131068&e)>>2}function Ki(e,t){return-131069&e|t<<2}function Zi(e){return 1|e}function Xi(e,t){const n=e.contentQueries;if(null!==n)for(let i=0;iIe&&Ui(e,t,0,wt()),n(i,r)}finally{zt(s)}}function ar(e,t,n){if(Fe(t)){const i=t.directiveEnd;for(let r=t.directiveStart;r0&&function e(t){for(let i=Hi(t);null!==i;i=Wi(i))for(let t=Pe;t0&&e(n)}const n=t[1].components;if(null!==n)for(let i=0;i0&&e(r)}}(n)}}function Lr(e,t){const n=st(t,e),i=n[1];!function(e,t){for(let n=t.length;nPromise.resolve(null))();function Nr(e){return e[7]||(e[7]=[])}function Fr(e,t){const n=e[9],i=n?n.get(En,null):null;i&&i.handleError(t)}function Yr(e,t,n,i,r){for(let s=0;s0&&(e[n-1][4]=i[4]);const o=he(e,Pe+t);ns(i[1],r=i,r[11],2,null,null),r[0]=null,r[6]=null;const a=o[19];null!==a&&a.detachView(o[1]),i[3]=null,i[4]=null,i[2]&=-129}var r;return i}function Br(e,t){if(!(256&t[2])){const n=t[11];Ze(n)&&n.destroyNode&&ns(e,t,n,3,null,null),function(e){let t=e[13];if(!t)return Ur(e[1],e);for(;t;){let n=null;if(je(t))n=t[13];else{const e=t[10];e&&(n=e)}if(!n){for(;t&&!t[4]&&t!==e;)je(t)&&Ur(t[1],t),t=t[3];null===t&&(t=e),je(t)&&Ur(t[1],t),n=t&&t[4]}t=n}}(t)}}function Ur(e,t){if(!(256&t[2])){t[2]&=-129,t[2]|=256,function(e,t){let n;if(null!=e&&null!=(n=e.destroyHooks))for(let i=0;i=0?e[a]():e[-a].unsubscribe(),i+=2}else n[i].call(e[n[i+1]]);t[7]=null}}(e,t),1===t[1].type&&Ze(t[11])&&t[11].destroy();const n=t[17];if(null!==n&&Ne(t[3])){n!==t[3]&&Wr(n,t);const i=t[19];null!==i&&i.detachView(e)}}}function qr(e,t,n){let i=t.parent;for(;null!=i&&(3===i.type||4===i.type);)i=(t=i).parent;if(null===i)return n[0];if(t&&4===t.type&&4&t.flags)return nt(t,n).parentNode;if(2&i.flags){const t=e.data,n=t[t[i.index].directiveStart].encapsulation;if(n!==_e.ShadowDom&&n!==_e.Native)return null}return nt(i,n)}function Gr(e,t,n,i){Ze(e)?e.insertBefore(t,n,i):t.insertBefore(n,i,!0)}function Jr(e,t,n){Ze(e)?e.appendChild(t,n):t.appendChild(n)}function Qr(e,t,n,i){null!==i?Gr(e,t,n,i):Jr(e,t,n)}function Kr(e,t){return Ze(e)?e.parentNode(t):t.parentNode}function Zr(e,t){return 3===e.type||4===e.type?nt(e,t):null}function Xr(e,t,n,i){const r=qr(e,i,t);if(null!=r){const e=t[11],s=Zr(i.parent||t[6],t);if(Array.isArray(n))for(let t=0;t-1&&this._viewContainerRef.detach(e),this._viewContainerRef=null}Br(this._lView[1],this._lView)}onDestroy(e){hr(this._lView[1],this._lView,null,e)}markForCheck(){Er(this._cdRefInjectingView||this._lView)}detach(){this._lView[2]&=-129}reattach(){this._lView[2]|=128}detectChanges(){Ar(this._lView[1],this._lView,this.context)}checkNoChanges(){!function(e,t,n){St(!0);try{Ar(e,t,n)}finally{St(!1)}}(this._lView[1],this._lView,this.context)}attachToViewContainerRef(e){if(this._appRef)throw new Error("This view is already attached directly to the ApplicationRef!");this._viewContainerRef=e}detachFromAppRef(){var e;this._appRef=null,ns(this._lView[1],e=this._lView,e[11],2,null,null)}attachToAppRef(e){if(this._viewContainerRef)throw new Error("This view is already attached to a ViewContainer!");this._appRef=e}}class cs extends as{constructor(e){super(e),this._view=e}detectChanges(){Ir(this._view)}checkNoChanges(){!function(e){St(!0);try{Ir(e)}finally{St(!1)}}(this._view)}get context(){return null}}let ls,us,ds;function hs(e,t,n){return ls||(ls=class extends e{}),new ls(nt(t,n))}function fs(e,t,n,i){return us||(us=class extends e{constructor(e,t,n){super(),this._declarationView=e,this._declarationTContainer=t,this.elementRef=n}createEmbeddedView(e){const t=this._declarationTContainer.tViews,n=tr(this._declarationView,t,e,16,null,t.declTNode,null,null,null,null);n[17]=this._declarationView[this._declarationTContainer.index];const i=this._declarationView[19];return null!==i&&(n[19]=i.createEmbeddedView(t)),ir(t,n,e),new as(n)}}),0===n.type?new us(i,n,hs(t,n,i)):null}function ps(e,t,n,i){let r;ds||(ds=class extends e{constructor(e,t,n){super(),this._lContainer=e,this._hostTNode=t,this._hostView=n}get element(){return hs(t,this._hostTNode,this._hostView)}get injector(){return new Dn(this._hostTNode,this._hostView)}get parentInjector(){const e=gn(this._hostTNode,this._hostView);if(tn(e)){const t=rn(e,this._hostView),n=nn(e);return new Dn(t[1].data[n+8],t)}return new Dn(null,this._hostView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(e){return null!==this._lContainer[8]&&this._lContainer[8][e]||null}get length(){return this._lContainer.length-Pe}createEmbeddedView(e,t,n){const i=e.createEmbeddedView(t||{});return this.insert(i,n),i}createComponent(e,t,n,i,r){const s=n||this.parentInjector;if(!r&&null==e.ngModule&&s){const e=s.get(ae,null);e&&(r=e)}const o=e.create(s,i,void 0,r);return this.insert(o.hostView,t),o}insert(e,t){const n=e._lView,i=n[1];if(e.destroyed)throw new Error("Cannot insert a destroyed View in a ViewContainer!");if(this.allocateContainerIfNeeded(),Ne(n[3])){const t=this.indexOf(e);if(-1!==t)this.detach(t);else{const t=n[3],i=new ds(t,t[6],t[3]);i.detach(i.indexOf(e))}}const r=this._adjustIndex(t),s=this._lContainer;!function(e,t,n,i){const r=Pe+i,s=n.length;i>0&&(n[r-1][4]=t),i{class e{}return e.__NG_ELEMENT_ID__=()=>gs(),e})();const gs=ms,_s=Function,ys=new U("Set Injector scope."),vs={},ws={},Ss=[];let Ms=void 0;function xs(){return void 0===Ms&&(Ms=new oe),Ms}function ks(e,t=null,n=null,i){return new Ds(e,n,t||xs(),i)}class Ds{constructor(e,t,n,i=null){this.parent=n,this.records=new Map,this.injectorDefTypes=new Set,this.onDestroy=new Set,this._destroyed=!1;const r=[];t&&ue(t,n=>this.processProvider(n,e,t)),ue([e],e=>this.processInjectorType(e,[],r)),this.records.set(q,Os(void 0,this));const s=this.records.get(ys);this.scope=null!=s?s.value:null,this.source=i||("object"==typeof e?null:C(e))}get destroyed(){return this._destroyed}destroy(){this.assertNotDestroyed(),this._destroyed=!0;try{this.onDestroy.forEach(e=>e.ngOnDestroy())}finally{this.records.clear(),this.onDestroy.clear(),this.injectorDefTypes.clear()}}get(e,t=G,n=m.Default){this.assertNotDestroyed();const i=ee(this);try{if(!(n&m.SkipSelf)){let t=this.records.get(e);if(void 0===t){const n=("function"==typeof(r=e)||"object"==typeof r&&r instanceof U)&&v(e);t=n&&this.injectableDefInScope(n)?Os(Ts(e),vs):null,this.records.set(e,t)}if(null!=t)return this.hydrate(e,t)}return(n&m.Self?xs():this.parent).get(e,t=n&m.Optional&&t===G?null:t)}catch(s){if("NullInjectorError"===s.name){if((s.ngTempTokenPath=s.ngTempTokenPath||[]).unshift(C(e)),i)throw s;return function(e,t,n,i){const r=e.ngTempTokenPath;throw t[Q]&&r.unshift(t[Q]),e.message=function(e,t,n,i=null){e=e&&"\n"===e.charAt(0)&&"\u0275"==e.charAt(1)?e.substr(2):e;let r=C(t);if(Array.isArray(t))r=t.map(C).join(" -> ");else if("object"==typeof t){let e=[];for(let n in t)if(t.hasOwnProperty(n)){let i=t[n];e.push(n+":"+("string"==typeof i?JSON.stringify(i):C(i)))}r=`{${e.join(", ")}}`}return`${n}${i?"("+i+")":""}[${r}]: ${e.replace(J,"\n ")}`}("\n"+e.message,r,n,i),e.ngTokenPath=r,e.ngTempTokenPath=null,e}(s,e,"R3InjectorError",this.source)}throw s}finally{ee(i)}var r}_resolveInjectorDefTypes(){this.injectorDefTypes.forEach(e=>this.get(e))}toString(){const e=[];return this.records.forEach((t,n)=>e.push(C(n))),`R3Injector[${e.join(", ")}]`}assertNotDestroyed(){if(this._destroyed)throw new Error("Injector has already been destroyed.")}processInjectorType(e,t,n){if(!(e=E(e)))return!1;let i=S(e);const r=null==i&&e.ngModule||void 0,s=void 0===r?e:r,o=-1!==n.indexOf(s);if(void 0!==r&&(i=S(r)),null==i)return!1;if(null!=i.imports&&!o){let e;n.push(s);try{ue(i.imports,i=>{this.processInjectorType(i,t,n)&&(void 0===e&&(e=[]),e.push(i))})}finally{}if(void 0!==e)for(let t=0;tthis.processProvider(e,n,i||Ss))}}this.injectorDefTypes.add(s),this.records.set(s,Os(i.factory,vs));const a=i.providers;if(null!=a&&!o){const t=e;ue(a,e=>this.processProvider(e,t,a))}return void 0!==r&&void 0!==e.providers}processProvider(e,t,n){let i=Rs(e=E(e))?e:E(e&&e.provide);const r=function(e,t,n){return Ls(e)?Os(void 0,e.useValue):Os(Cs(e),vs)}(e);if(Rs(e)||!0!==e.multi)this.records.get(i);else{let t=this.records.get(i);t||(t=Os(void 0,vs,!0),t.factory=()=>se(t.multi),this.records.set(i,t)),i=e,t.multi.push(e)}this.records.set(i,r)}hydrate(e,t){var n;return t.value===vs&&(t.value=ws,t.value=t.factory()),"object"==typeof t.value&&t.value&&null!==(n=t.value)&&"object"==typeof n&&"function"==typeof n.ngOnDestroy&&this.onDestroy.add(t.value),t.value}injectableDefInScope(e){return!!e.providedIn&&("string"==typeof e.providedIn?"any"===e.providedIn||e.providedIn===this.scope:this.injectorDefTypes.has(e.providedIn))}}function Ts(e){const t=v(e),n=null!==t?t.factory:Ee(e);if(null!==n)return n;const i=S(e);if(null!==i)return i.factory;if(e instanceof U)throw new Error(`Token ${C(e)} is missing a \u0275prov definition.`);if(e instanceof Function)return function(e){const t=e.length;if(t>0){const n=fe(t,"?");throw new Error(`Can't resolve all parameters for ${C(e)}: (${n.join(", ")}).`)}const n=function(e){const t=e&&(e[M]||e[D]||e[k]&&e[k]());if(t){const n=function(e){if(e.hasOwnProperty("name"))return e.name;const t=(""+e).match(/^function\s*([^\s(]+)/);return null===t?"":t[1]}(e);return console.warn(`DEPRECATED: DI is instantiating a token "${n}" that inherits its @Injectable decorator but does not provide one itself.\nThis will become an error in a future version of Angular. Please add @Injectable() to the "${n}" class.`),t}return null}(e);return null!==n?()=>n.factory(e):()=>new e}(e);throw new Error("unreachable")}function Cs(e,t,n){let i=void 0;if(Rs(e)){const t=E(e);return Ee(t)||Ts(t)}if(Ls(e))i=()=>E(e.useValue);else if((r=e)&&r.useFactory)i=()=>e.useFactory(...se(e.deps||[]));else if(function(e){return!(!e||!e.useExisting)}(e))i=()=>ie(E(e.useExisting));else{const t=E(e&&(e.useClass||e.provide));if(!function(e){return!!e.deps}(e))return Ee(t)||Ts(t);i=()=>new t(...se(e.deps))}var r;return i}function Os(e,t,n=!1){return{factory:e,value:t,multi:n?[]:void 0}}function Ls(e){return null!==e&&"object"==typeof e&&K in e}function Rs(e){return"function"==typeof e}const Es=function(e,t,n){return function(e,t=null,n=null,i){const r=ks(e,t,n,i);return r._resolveInjectorDefTypes(),r}({name:n},t,e,n)};let As=(()=>{class e{static create(e,t){return Array.isArray(e)?Es(e,t,""):Es(e.providers,e.parent,e.name||"")}}return e.THROW_IF_NOT_FOUND=G,e.NULL=new oe,e.\u0275prov=_({token:e,providedIn:"any",factory:()=>ie(q)}),e.__NG_ELEMENT_ID__=-1,e})();const Is=new U("AnalyzeForEntryComponents");function Ps(e,t,n){let i=n?e.styles:null,r=n?e.classes:null,s=0;if(null!==t)for(let o=0;o=0;i--){const r=e[i];r.hostVars=t+=r.hostVars,r.hostAttrs=Xt(r.hostAttrs,n=Xt(n,r.hostAttrs))}}(i)}function Fs(e){return e===ye?{}:e===ve?[]:e}function Ys(e,t){const n=e.viewQuery;e.viewQuery=n?(e,i)=>{t(e,i),n(e,i)}:t}function zs(e,t){const n=e.contentQueries;e.contentQueries=n?(e,i,r)=>{t(e,i,r),n(e,i,r)}:t}function $s(e,t){const n=e.hostBindings;e.hostBindings=n?(e,i)=>{t(e,i),n(e,i)}:t}let Hs=null;function Ws(){if(!Hs){const e=F.Symbol;if(e&&e.iterator)Hs=e.iterator;else{const e=Object.getOwnPropertyNames(Map.prototype);for(let t=0;ta(et(e[i.index])).target:i.index;if(Ze(n)){let o=null;if(!a&&c&&(o=function(e,t,n,i){const r=e.cleanup;if(null!=r)for(let s=0;sn?e[n]:null}"string"==typeof e&&(s+=2)}return null}(e,t,r,i.index)),null!==o)(o.__ngLastListenerFn__||o).__ngNextListenerFn__=s,o.__ngLastListenerFn__=s,d=!1;else{s=vo(i,t,s,!1);const e=n.listen(f.name||p,r,s);u.push(s,e),l&&l.push(r,b,m,m+1)}}else s=vo(i,t,s,!0),p.addEventListener(r,s,o),u.push(s),l&&l.push(r,b,m,o)}const h=i.outputs;let f;if(d&&null!==h&&(f=h[r])){const e=f.length;if(e)for(let n=0;n0;)t=t[15],e--;return t}(e,ht.lFrame.contextLView))[8]}(e)}function So(e,t){let n=null;const i=function(e){const t=e.attrs;if(null!=t){const e=t.indexOf(5);if(0==(1&e))return t[e+1]}return null}(e);for(let r=0;r=0}const Ao={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function Io(e){return e.substring(Ao.key,Ao.keyEnd)}function Po(e,t){const n=Ao.textEnd;return n===t?-1:(t=Ao.keyEnd=function(e,t,n){for(;t32;)t++;return t}(e,Ao.key=t,n),jo(e,t,n))}function jo(e,t,n){for(;t=0;n=Po(t,n))pe(e,Io(t),!0)}function $o(e,t,n,i){const r=pt(),s=mt(),o=Dt(2);s.firstUpdatePass&&Vo(s,e,o,i),t!==zi&&Js(r,o,t)&&qo(s,s.data[Yt()+Ie],r,r[11],e,r[o+1]=function(e,t){return null==e||("string"==typeof t?e+=t:"object"==typeof e&&(e=C(Yn(e)))),e}(t,n),i,o)}function Ho(e,t,n,i){const r=mt(),s=Dt(2);r.firstUpdatePass&&Vo(r,null,s,i);const o=pt();if(n!==zi&&Js(o,s,n)){const a=r.data[Yt()+Ie];if(Qo(a,i)&&!Wo(r,s)){let e=i?a.classesWithoutHost:a.stylesWithoutHost;null!==e&&(n=O(e,n||"")),ao(r,a,o,n,i)}else!function(e,t,n,i,r,s,o,a){r===zi&&(r=Lo);let c=0,l=0,u=0=e.expandoStartIndex}function Vo(e,t,n,i){const r=e.data;if(null===r[n+1]){const s=r[Yt()+Ie],o=Wo(e,n);Qo(s,i)&&null===t&&!o&&(t=!1),t=function(e,t,n,i){const r=Ot(e);let s=i?t.residualClasses:t.residualStyles;if(null===r)0===(i?t.classBindings:t.styleBindings)&&(n=Uo(n=Bo(null,e,t,n,i),t.attrs,i),s=null);else{const o=t.directiveStylingLast;if(-1===o||e[o]!==r)if(n=Bo(r,e,t,n,i),null===s){let n=function(e,t,n){const i=n?t.classBindings:t.styleBindings;if(0!==Qi(i))return e[Gi(i)]}(e,t,i);void 0!==n&&Array.isArray(n)&&(n=Bo(null,e,t,n[1],i),n=Uo(n,t.attrs,i),function(e,t,n,i){e[Gi(n?t.classBindings:t.styleBindings)]=i}(e,t,i,n))}else s=function(e,t,n){let i=void 0;const r=t.directiveEnd;for(let s=1+t.directiveStylingLast;s0)&&(u=!0)}else l=n;if(r)if(0!==c){const t=Gi(e[a+1]);e[i+1]=qi(t,a),0!==t&&(e[t+1]=Ki(e[t+1],i)),e[a+1]=131071&e[a+1]|i<<17}else e[i+1]=qi(a,0),0!==a&&(e[a+1]=Ki(e[a+1],i)),a=i;else e[i+1]=qi(c,0),0===a?a=i:e[c+1]=Ki(e[c+1],i),c=i;u&&(e[i+1]=Ji(e[i+1])),Ro(e,l,i,!0),Ro(e,l,i,!1),function(e,t,n,i,r){const s=r?e.residualClasses:e.residualStyles;null!=s&&"string"==typeof t&&be(s,t)>=0&&(n[i+1]=Zi(n[i+1]))}(t,l,e,i,s),o=qi(a,c),s?t.classBindings=o:t.styleBindings=o}(r,s,t,n,o,i)}}function Bo(e,t,n,i,r){let s=null;const o=n.directiveEnd;let a=n.directiveStylingLast;for(-1===a?a=n.directiveStart:a++;a0;){const t=e[r],s=Array.isArray(t),c=s?t[1]:t,l=null===c;let u=n[r+1];u===zi&&(u=l?Lo:void 0);let d=l?me(u,i):c===i?u:void 0;if(s&&!Jo(d)&&(d=me(t,i)),Jo(d)&&(a=d,o))return a;const h=e[r+1];r=o?Gi(h):Qi(h)}if(null!==t){let e=s?t.residualClasses:t.residualStyles;null!=e&&(a=me(e,i))}return a}function Jo(e){return void 0!==e}function Qo(e,t){return 0!=(e.flags&(t?16:32))}function Ko(e,t=""){const n=pt(),i=mt(),r=e+Ie,s=i.firstCreatePass?nr(i,e,2,null,null):i.data[r],o=n[r]=Hr(t,n[11]);Xr(i,n,o,s),_t(s,!1)}function Zo(e){return Xo("",e,""),Zo}function Xo(e,t,n){const i=pt(),r=eo(i,e,t,n);return r!==zi&&zr(i,Yt(),r),Xo}function ea(e,t,n,i,r){const s=pt(),o=to(s,e,t,n,i,r);return o!==zi&&zr(s,Yt(),o),ea}function ta(e,t,n,i,r,s,o){const a=pt(),c=function(e,t,n,i,r,s,o,a){const c=Ks(e,xt(),n,r,o);return Dt(3),c?t+sn(n)+i+sn(r)+s+sn(o)+a:zi}(a,e,t,n,i,r,s,o);return c!==zi&&zr(a,Yt(),c),ta}function na(e,t,n){Ho(pe,zo,eo(pt(),e,t,n),!0)}function ia(e,t,n,i,r){Ho(pe,zo,to(pt(),e,t,n,i,r),!0)}function ra(e,t,n,i,r,s,o,a,c){Ho(pe,zo,function(e,t,n,i,r,s,o,a,c,l){const u=Zs(e,xt(),n,r,o,c);return Dt(4),u?t+sn(n)+i+sn(r)+s+sn(o)+a+sn(c)+l:zi}(pt(),e,t,n,i,r,s,o,a,c),!0)}function sa(e,t,n){const i=pt();return Js(i,kt(),t)&&pr(mt(),$t(),i,e,t,i[11],n,!0),sa}function oa(e,t,n){const i=pt();if(Js(i,kt(),t)){const r=mt(),s=$t();pr(r,s,i,e,t,function(e,t,n){return(null===e||$e(e))&&(n=function(e){for(;Array.isArray(e);){if("object"==typeof e[1])return e;e=e[0]}return null}(n[t.index])),n[11]}(Ot(r.data),s,i),n,!0)}return oa}function aa(e,t,n,i,r){if(e=E(e),Array.isArray(e))for(let s=0;s>20;if(Rs(e)||!e.multi){const i=new Jt(c,r,ro),f=ua(a,t,r?u:u+h,d);-1===f?(_n(pn(l,o),s,a),ca(s,e,t.length),t.push(a),l.directiveStart++,l.directiveEnd++,r&&(l.providerIndexes+=1048576),n.push(i),o.push(i)):(n[f]=i,o[f]=i)}else{const f=ua(a,t,u+h,d),p=ua(a,t,u,u+h),m=f>=0&&n[f],b=p>=0&&n[p];if(r&&!b||!r&&!m){_n(pn(l,o),s,a);const u=function(e,t,n,i,r){const s=new Jt(e,n,ro);return s.multi=[],s.index=t,s.componentProviders=0,la(s,r,i&&!n),s}(r?ha:da,n.length,r,i,c);!r&&b&&(n[p].providerFactory=u),ca(s,e,t.length,0),t.push(a),l.directiveStart++,l.directiveEnd++,r&&(l.providerIndexes+=1048576),n.push(u),o.push(u)}else ca(s,e,f>-1?f:p,la(n[r?p:f],c,!r&&i));!r&&i&&b&&n[p].componentProviders++}}}function ca(e,t,n,i){const r=Rs(t);if(r||t.useClass){const s=(t.useClass||t).prototype.ngOnDestroy;if(s){const o=e.destroyHooks||(e.destroyHooks=[]);if(!r&&t.multi){const e=o.indexOf(n);-1===e?o.push(n,[i,s]):o[e+1].push(i,s)}else o.push(n,s)}}}function la(e,t,n){return n&&e.componentProviders++,e.multi.push(t)-1}function ua(e,t,n,i){for(let r=n;r{n.providersResolver=(n,i)=>function(e,t,n){const i=mt();if(i.firstCreatePass){const r=$e(e);aa(n,i.data,i.blueprint,r,!0),aa(t,i.data,i.blueprint,r,!1)}}(n,i?i(e):e,t)}}class ma{}class ba{}class ga{resolveComponentFactory(e){throw function(e){const t=Error(`No component factory found for ${C(e)}. Did you add it to @NgModule.entryComponents?`);return t.ngComponent=e,t}(e)}}let _a=(()=>{class e{}return e.NULL=new ga,e})(),ya=(()=>{class e{constructor(e){this.nativeElement=e}}return e.__NG_ELEMENT_ID__=()=>va(e),e})();const va=function(e){return hs(e,gt(),pt())};class wa{}var Sa=function(e){return e[e.Important=1]="Important",e[e.DashCase=2]="DashCase",e}({});let Ma=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>xa(),e})();const xa=function(){const e=pt(),t=st(gt().index,e);return function(e){const t=e[11];if(Ze(t))return t;throw new Error("Cannot inject Renderer2 when the application uses Renderer3!")}(je(t)?t:e)};let ka=(()=>{class e{}return e.\u0275prov=_({token:e,providedIn:"root",factory:()=>null}),e})();class Da{constructor(e){this.full=e,this.major=e.split(".")[0],this.minor=e.split(".")[1],this.patch=e.split(".").slice(2).join(".")}}const Ta=new Da("10.1.5");class Ca{constructor(){}supports(e){return Bs(e)}create(e){return new La(e)}}const Oa=(e,t)=>t;class La{constructor(e){this.length=0,this._linkedRecords=null,this._unlinkedRecords=null,this._previousItHead=null,this._itHead=null,this._itTail=null,this._additionsHead=null,this._additionsTail=null,this._movesHead=null,this._movesTail=null,this._removalsHead=null,this._removalsTail=null,this._identityChangesHead=null,this._identityChangesTail=null,this._trackByFn=e||Oa}forEachItem(e){let t;for(t=this._itHead;null!==t;t=t._next)e(t)}forEachOperation(e){let t=this._itHead,n=this._removalsHead,i=0,r=null;for(;t||n;){const s=!n||t&&t.currentIndex{i=this._trackByFn(t,e),null!==r&&Object.is(r.trackById,i)?(s&&(r=this._verifyReinsertion(r,e,i,t)),Object.is(r.item,e)||this._addIdentityChange(r,e)):(r=this._mismatch(r,e,i,t),s=!0),r=r._next,t++}),this.length=t;return this._truncate(r),this.collection=e,this.isDirty}get isDirty(){return null!==this._additionsHead||null!==this._movesHead||null!==this._removalsHead||null!==this._identityChangesHead}_reset(){if(this.isDirty){let e;for(e=this._previousItHead=this._itHead;null!==e;e=e._next)e._nextPrevious=e._next;for(e=this._additionsHead;null!==e;e=e._nextAdded)e.previousIndex=e.currentIndex;for(this._additionsHead=this._additionsTail=null,e=this._movesHead;null!==e;e=e._nextMoved)e.previousIndex=e.currentIndex;this._movesHead=this._movesTail=null,this._removalsHead=this._removalsTail=null,this._identityChangesHead=this._identityChangesTail=null}}_mismatch(e,t,n,i){let r;return null===e?r=this._itTail:(r=e._prev,this._remove(e)),null!==(e=null===this._linkedRecords?null:this._linkedRecords.get(n,i))?(Object.is(e.item,t)||this._addIdentityChange(e,t),this._moveAfter(e,r,i)):null!==(e=null===this._unlinkedRecords?null:this._unlinkedRecords.get(n,null))?(Object.is(e.item,t)||this._addIdentityChange(e,t),this._reinsertAfter(e,r,i)):e=this._addAfter(new Ra(t,n),r,i),e}_verifyReinsertion(e,t,n,i){let r=null===this._unlinkedRecords?null:this._unlinkedRecords.get(n,null);return null!==r?e=this._reinsertAfter(r,e._prev,i):e.currentIndex!=i&&(e.currentIndex=i,this._addToMoves(e,i)),e}_truncate(e){for(;null!==e;){const t=e._next;this._addToRemovals(this._unlink(e)),e=t}null!==this._unlinkedRecords&&this._unlinkedRecords.clear(),null!==this._additionsTail&&(this._additionsTail._nextAdded=null),null!==this._movesTail&&(this._movesTail._nextMoved=null),null!==this._itTail&&(this._itTail._next=null),null!==this._removalsTail&&(this._removalsTail._nextRemoved=null),null!==this._identityChangesTail&&(this._identityChangesTail._nextIdentityChange=null)}_reinsertAfter(e,t,n){null!==this._unlinkedRecords&&this._unlinkedRecords.remove(e);const i=e._prevRemoved,r=e._nextRemoved;return null===i?this._removalsHead=r:i._nextRemoved=r,null===r?this._removalsTail=i:r._prevRemoved=i,this._insertAfter(e,t,n),this._addToMoves(e,n),e}_moveAfter(e,t,n){return this._unlink(e),this._insertAfter(e,t,n),this._addToMoves(e,n),e}_addAfter(e,t,n){return this._insertAfter(e,t,n),this._additionsTail=null===this._additionsTail?this._additionsHead=e:this._additionsTail._nextAdded=e,e}_insertAfter(e,t,n){const i=null===t?this._itHead:t._next;return e._next=i,e._prev=t,null===i?this._itTail=e:i._prev=e,null===t?this._itHead=e:t._next=e,null===this._linkedRecords&&(this._linkedRecords=new Aa),this._linkedRecords.put(e),e.currentIndex=n,e}_remove(e){return this._addToRemovals(this._unlink(e))}_unlink(e){null!==this._linkedRecords&&this._linkedRecords.remove(e);const t=e._prev,n=e._next;return null===t?this._itHead=n:t._next=n,null===n?this._itTail=t:n._prev=t,e}_addToMoves(e,t){return e.previousIndex===t||(this._movesTail=null===this._movesTail?this._movesHead=e:this._movesTail._nextMoved=e),e}_addToRemovals(e){return null===this._unlinkedRecords&&(this._unlinkedRecords=new Aa),this._unlinkedRecords.put(e),e.currentIndex=null,e._nextRemoved=null,null===this._removalsTail?(this._removalsTail=this._removalsHead=e,e._prevRemoved=null):(e._prevRemoved=this._removalsTail,this._removalsTail=this._removalsTail._nextRemoved=e),e}_addIdentityChange(e,t){return e.item=t,this._identityChangesTail=null===this._identityChangesTail?this._identityChangesHead=e:this._identityChangesTail._nextIdentityChange=e,e}}class Ra{constructor(e,t){this.item=e,this.trackById=t,this.currentIndex=null,this.previousIndex=null,this._nextPrevious=null,this._prev=null,this._next=null,this._prevDup=null,this._nextDup=null,this._prevRemoved=null,this._nextRemoved=null,this._nextAdded=null,this._nextMoved=null,this._nextIdentityChange=null}}class Ea{constructor(){this._head=null,this._tail=null}add(e){null===this._head?(this._head=this._tail=e,e._nextDup=null,e._prevDup=null):(this._tail._nextDup=e,e._prevDup=this._tail,e._nextDup=null,this._tail=e)}get(e,t){let n;for(n=this._head;null!==n;n=n._nextDup)if((null===t||t<=n.currentIndex)&&Object.is(n.trackById,e))return n;return null}remove(e){const t=e._prevDup,n=e._nextDup;return null===t?this._head=n:t._nextDup=n,null===n?this._tail=t:n._prevDup=t,null===this._head}}class Aa{constructor(){this.map=new Map}put(e){const t=e.trackById;let n=this.map.get(t);n||(n=new Ea,this.map.set(t,n)),n.add(e)}get(e,t){const n=this.map.get(e);return n?n.get(e,t):null}remove(e){const t=e.trackById;return this.map.get(t).remove(e)&&this.map.delete(t),e}get isEmpty(){return 0===this.map.size}clear(){this.map.clear()}}function Ia(e,t,n){const i=e.previousIndex;if(null===i)return i;let r=0;return n&&i{if(t&&t.key===n)this._maybeAddToChanges(t,e),this._appendAfter=t,t=t._next;else{const i=this._getOrCreateRecordForKey(n,e);t=this._insertBeforeOrAppend(t,i)}}),t){t._prev&&(t._prev._next=null),this._removalsHead=t;for(let e=t;null!==e;e=e._nextRemoved)e===this._mapHead&&(this._mapHead=null),this._records.delete(e.key),e._nextRemoved=e._next,e.previousValue=e.currentValue,e.currentValue=null,e._prev=null,e._next=null}return this._changesTail&&(this._changesTail._nextChanged=null),this._additionsTail&&(this._additionsTail._nextAdded=null),this.isDirty}_insertBeforeOrAppend(e,t){if(e){const n=e._prev;return t._next=e,t._prev=n,e._prev=t,n&&(n._next=t),e===this._mapHead&&(this._mapHead=t),this._appendAfter=e,e}return this._appendAfter?(this._appendAfter._next=t,t._prev=this._appendAfter):this._mapHead=t,this._appendAfter=t,null}_getOrCreateRecordForKey(e,t){if(this._records.has(e)){const n=this._records.get(e);this._maybeAddToChanges(n,t);const i=n._prev,r=n._next;return i&&(i._next=r),r&&(r._prev=i),n._next=null,n._prev=null,n}const n=new Na(e);return this._records.set(e,n),n.currentValue=t,this._addToAdditions(n),n}_reset(){if(this.isDirty){let e;for(this._previousMapHead=this._mapHead,e=this._previousMapHead;null!==e;e=e._next)e._nextPrevious=e._next;for(e=this._changesHead;null!==e;e=e._nextChanged)e.previousValue=e.currentValue;for(e=this._additionsHead;null!=e;e=e._nextAdded)e.previousValue=e.currentValue;this._changesHead=this._changesTail=null,this._additionsHead=this._additionsTail=null,this._removalsHead=null}}_maybeAddToChanges(e,t){Object.is(t,e.currentValue)||(e.previousValue=e.currentValue,e.currentValue=t,this._addToChanges(e))}_addToAdditions(e){null===this._additionsHead?this._additionsHead=this._additionsTail=e:(this._additionsTail._nextAdded=e,this._additionsTail=e)}_addToChanges(e){null===this._changesHead?this._changesHead=this._changesTail=e:(this._changesTail._nextChanged=e,this._changesTail=e)}_forEach(e,t){e instanceof Map?e.forEach(t):Object.keys(e).forEach(n=>t(e[n],n))}}class Na{constructor(e){this.key=e,this.previousValue=null,this.currentValue=null,this._nextPrevious=null,this._next=null,this._prev=null,this._nextAdded=null,this._nextRemoved=null,this._nextChanged=null}}let Fa=(()=>{class e{constructor(e){this.factories=e}static create(t,n){if(null!=n){const e=n.factories.slice();t=t.concat(e)}return new e(t)}static extend(t){return{provide:e,useFactory:n=>{if(!n)throw new Error("Cannot extend IterableDiffers without a parent injector");return e.create(t,n)},deps:[[e,new p,new h]]}}find(e){const t=this.factories.find(t=>t.supports(e));if(null!=t)return t;throw new Error(`Cannot find a differ supporting object '${e}' of type '${n=e,n.name||typeof n}'`);var n}}return e.\u0275prov=_({token:e,providedIn:"root",factory:()=>new e([new Ca])}),e})(),Ya=(()=>{class e{constructor(e){this.factories=e}static create(t,n){if(n){const e=n.factories.slice();t=t.concat(e)}return new e(t)}static extend(t){return{provide:e,useFactory:n=>{if(!n)throw new Error("Cannot extend KeyValueDiffers without a parent injector");return e.create(t,n)},deps:[[e,new p,new h]]}}find(e){const t=this.factories.find(t=>t.supports(e));if(t)return t;throw new Error(`Cannot find a differ supporting object '${e}'`)}}return e.\u0275prov=_({token:e,providedIn:"root",factory:()=>new e([new Pa])}),e})();const za=[new Pa],$a=new Fa([new Ca]),Ha=new Ya(za);let Wa=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>Va(e,ya),e})();const Va=function(e,t){return fs(e,t,gt(),pt())};let Ba=(()=>{class e{}return e.__NG_ELEMENT_ID__=()=>Ua(e,ya),e})();const Ua=function(e,t){return ps(e,t,gt(),pt())},qa={};class Ga extends _a{constructor(e){super(),this.ngModule=e}resolveComponentFactory(e){const t=Re(e);return new Ka(t,this.ngModule)}}function Ja(e){const t=[];for(let n in e)e.hasOwnProperty(n)&&t.push({propName:e[n],templateName:n});return t}const Qa=new U("SCHEDULER_TOKEN",{providedIn:"root",factory:()=>an});class Ka extends ba{constructor(e,t){super(),this.componentDef=e,this.ngModule=t,this.componentType=e.type,this.selector=e.selectors.map(Yi).join(","),this.ngContentSelectors=e.ngContentSelectors?e.ngContentSelectors:[],this.isBoundToModule=!!t}get inputs(){return Ja(this.componentDef.inputs)}get outputs(){return Ja(this.componentDef.outputs)}create(e,t,n,i){const r=(i=i||this.ngModule)?function(e,t){return{get:(n,i,r)=>{const s=e.get(n,qa,r);return s!==qa||i===qa?s:t.get(n,i,r)}}}(e,i.injector):e,s=r.get(wa,Xe),o=r.get(ka,null),a=s.createRenderer(null,this.componentDef),c=this.componentDef.selectors[0][0]||"div",l=n?function(e,t,n){if(Ze(e))return e.selectRootElement(t,n===_e.ShadowDom);let i="string"==typeof t?e.querySelector(t):t;return i.textContent="",i}(a,n,this.componentDef.encapsulation):er(c,s.createRenderer(null,this.componentDef),function(e){const t=e.toLowerCase();return"svg"===t?"http://www.w3.org/2000/svg":"math"===t?"http://www.w3.org/1998/MathML/":null}(c)),u=this.componentDef.onPush?576:528,d={components:[],scheduler:an,clean:jr,playerHandler:null,flags:0},h=dr(0,null,null,1,0,null,null,null,null,null),f=tr(null,h,d,u,null,null,s,a,o,r);let p,m;At(f);try{const e=function(e,t,n,i,r,s){const o=n[1];n[20]=e;const a=nr(o,0,2,null,null),c=a.mergedAttrs=t.hostAttrs;null!==c&&(Ps(a,c,!0),null!==e&&(Qt(r,e,c),null!==a.classes&&os(r,e,a.classes),null!==a.styles&&ss(r,e,a.styles)));const l=i.createRenderer(e,t),u=tr(n,ur(t),null,t.onPush?64:16,n[20],a,i,l,null,null);return o.firstCreatePass&&(_n(pn(a,n),o,t.type),vr(o,a),Sr(a,n.length,1)),Rr(n,u),n[20]=u}(l,this.componentDef,f,s,a);if(l)if(n)Qt(a,l,["ng-version",Ta.full]);else{const{attrs:e,classes:t}=function(e){const t=[],n=[];let i=1,r=2;for(;i0&&os(a,l,t.join(" "))}if(m=it(h,0),void 0!==t){const e=m.projection=[];for(let n=0;ne(o,t)),t.contentQueries&&t.contentQueries(1,o,n.length-1);const a=gt();if(s.firstCreatePass&&(null!==t.hostBindings||null!==t.hostAttrs)){zt(a.index-Ie);const e=n[1];br(e,t),gr(e,n,t.hostVars),_r(t,o)}return o}(e,this.componentDef,f,d,[js]),ir(h,f,null)}finally{Ft()}return new Za(this.componentType,p,hs(ya,m,f),f,m)}}class Za extends ma{constructor(e,t,n,i,r){super(),this.location=n,this._rootLView=i,this._tNode=r,this.destroyCbs=[],this.instance=t,this.hostView=this.changeDetectorRef=new cs(i),this.componentType=e}get injector(){return new Dn(this._tNode,this._rootLView)}destroy(){this.destroyCbs&&(this.destroyCbs.forEach(e=>e()),this.destroyCbs=null,!this.hostView.destroyed&&this.hostView.destroy())}onDestroy(e){this.destroyCbs&&this.destroyCbs.push(e)}}const Xa=void 0;var ec=["en",[["a","p"],["AM","PM"],Xa],[["AM","PM"],Xa,Xa],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],Xa,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],Xa,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm a","h:mm:ss a","h:mm:ss a z","h:mm:ss a zzzz"],["{1}, {0}",Xa,"{1} 'at' {0}",Xa],[".",",",";","%","+","-","E","\xd7","\u2030","\u221e","NaN",":"],["#,##0.###","#,##0%","\xa4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",function(e){let t=Math.floor(Math.abs(e)),n=e.toString().replace(/^[^.]*\.?/,"").length;return 1===t&&0===n?1:5}];let tc={};function nc(e,t,n){"string"!=typeof t&&(n=t,t=e[ac.LocaleId]),t=t.toLowerCase().replace(/_/g,"-"),tc[t]=e,n&&(tc[t][ac.ExtraData]=n)}function ic(e){const t=function(e){return e.toLowerCase().replace(/_/g,"-")}(e);let n=oc(t);if(n)return n;const i=t.split("-")[0];if(n=oc(i),n)return n;if("en"===i)return ec;throw new Error(`Missing locale data for the locale "${e}".`)}function rc(e){return ic(e)[ac.CurrencyCode]||null}function sc(e){return ic(e)[ac.PluralCase]}function oc(e){return e in tc||(tc[e]=F.ng&&F.ng.common&&F.ng.common.locales&&F.ng.common.locales[e]),tc[e]}var ac=function(e){return e[e.LocaleId=0]="LocaleId",e[e.DayPeriodsFormat=1]="DayPeriodsFormat",e[e.DayPeriodsStandalone=2]="DayPeriodsStandalone",e[e.DaysFormat=3]="DaysFormat",e[e.DaysStandalone=4]="DaysStandalone",e[e.MonthsFormat=5]="MonthsFormat",e[e.MonthsStandalone=6]="MonthsStandalone",e[e.Eras=7]="Eras",e[e.FirstDayOfWeek=8]="FirstDayOfWeek",e[e.WeekendRange=9]="WeekendRange",e[e.DateFormat=10]="DateFormat",e[e.TimeFormat=11]="TimeFormat",e[e.DateTimeFormat=12]="DateTimeFormat",e[e.NumberSymbols=13]="NumberSymbols",e[e.NumberFormats=14]="NumberFormats",e[e.CurrencyCode=15]="CurrencyCode",e[e.CurrencySymbol=16]="CurrencySymbol",e[e.CurrencyName=17]="CurrencyName",e[e.Currencies=18]="Currencies",e[e.Directionality=19]="Directionality",e[e.PluralCase=20]="PluralCase",e[e.ExtraData=21]="ExtraData",e}({});const cc=["zero","one","two","few","many"],lc="en-US";let uc=lc;function dc(e){var t,n;n="Expected localeId to be defined",null==(t=e)&&function(e,t,n,i){throw new Error("ASSERTION ERROR: "+e+` [Expected=> null != ${t} <=Actual]`)}(n,t),"string"==typeof e&&(uc=e.toLowerCase().replace(/_/g,"-"))}const hc={marker:"element"},fc={marker:"comment"},pc=[];let mc=-1,bc=0,gc=0;function _c(e,t,n,i){const r=i[11];let s=null,o=null;const a=[];for(let c=0;c>>17;let u;u=r===t?i[6]:it(e,r),o=Sc(e,s,u,o,i);break;case 0:const d=l>=0,h=(d?l:~l)>>>3;a.push(h),o=s,s=it(e,h),s&&_t(s,d);break;case 5:o=s=it(e,l>>>3),_t(s,!1);break;case 4:const f=n[++c],p=n[++c];kr(it(e,l>>>3),i,f,p,null,null);break;default:throw new Error(`Unable to determine the type of mutate operation for "${l}"`)}else switch(l){case fc:const t=n[++c],u=n[++c],d=r.createComment(t);o=s,s=xc(e,i,u,4,d,null),a.push(u),Ti(d,i),vt();break;case hc:const h=n[++c],f=n[++c];o=s,s=xc(e,i,f,2,r.createElement(h),h),a.push(f);break;default:throw new Error(`Unable to determine the type of mutate operation for "${l}"`)}}return vt(),a}function yc(e,t,n,i,r,s){let o=!1;for(let a=0;a>>2;switch(3&a){case 1:const a=i[++c],u=i[++c];pr(e,it(e,l),n,a,s,n[11],u,!1);break;case 0:zr(n,l,s);break;case 2:o=wc(e,t,i[++c],n,s);break;case 3:vc(e,t,i[++c],r,n,o)}}}}a+=l}}function vc(e,t,n,i,r,s){const o=t[n],a=r[o.currentCaseLViewIndex];null!==a&&yc(e,t,r,o.update[a],i,s?-1:bc)}function wc(e,t,n,i,r){!function e(t,n,i,r){const s=n[i],o=r[s.currentCaseLViewIndex];if(null!==o){const i=s.remove[o];for(let s=0;s>>3;switch(7&o){case 3:Mc(t,r,a,!1);break;case 6:e(t,n,a,r)}}}}(e,t,n,i);let s=!1;const o=t[n],a=function(e,t){let n=e.cases.indexOf(t);if(-1===n)switch(e.type){case 1:{const i=function(e,t){const n=sc(t)(parseInt(e,10)),i=cc[n];return void 0!==i?i:"other"}(t,uc);n=e.cases.indexOf(i),-1===n&&"other"!==i&&(n=e.cases.indexOf("other"));break}case 0:n=e.cases.indexOf("other")}return n}(o,r);return i[o.currentCaseLViewIndex]=-1!==a?a:null,a>-1&&(_c(e,-1,o.create[a],i),s=!0),s}function Sc(e,t,n,i,r){const s=t.next;i||(i=n),i===n&&t!==n.child?(t.next=n.child,null===t.parent?e.firstChild=t:n.child=t):i!==n&&t!==i.next?(t.next=i.next,i.next=t):t.next=null,n!==r[6]&&(t.parent=n);let o=t.next;for(;o;)o.next===t&&(o.next=s),o=o.next;if(1===t.type)return is(e,r,t),t;Xr(e,r,nt(t,r),t);const a=r[t.index];return 0!==t.type&&Ne(a)&&Xr(e,r,a[7],t),t}function Mc(e,t,n,i){const r=it(e,n),s=tt(n,t);s&&es(t[11],s);const o=rt(t,n);if(Ne(o)){const e=o;0!==r.type&&es(t[11],e[7])}i&&r&&(r.flags|=64)}function xc(e,t,n,i,r,s){const o=gt();t[n+Ie]=r;const a=nr(e,n,i,s,null);return o&&o.next===a&&(o.next=null),a}const kc=/\ufffd(\d+):?\d*\ufffd/gi,Dc=/({\s*\ufffd\d+:?\d*\ufffd\s*,\s*\S{6}\s*,[\s\S]*})/gi,Tc=/\ufffd(\d+)\ufffd/,Cc=/^\s*(\ufffd\d+:?\d*\ufffd)\s*,\s*(select|plural)\s*,/;let Oc;const Lc=[],Rc=/\ufffd\/?\*(\d+:\d+)\ufffd/gi,Ec=/\ufffd(\/?[#*!]\d+):?\d*\ufffd/gi,Ac=/\uE500/g;function Ic(e,t,n,i=null){const r=[null,null],s=e.split(kc);let o=0;for(let a=0;an.length&&n.push(r)}return{type:i,mainBinding:r,cases:t,values:n}}function Hc(e,t,n,i,r){const s=Kn(Ke()).getInertBodyElement(e);if(!s)throw new Error("Unable to generate inert body element");const o={vars:1,childIcus:[],create:[],remove:[],update:[]};return function e(t,n,i,r,s,o){if(t){const a=[];for(;t;){const c=t.nextSibling,l=o+ ++n.vars;switch(t.nodeType){case Node.ELEMENT_NODE:const c=t,u=c.tagName.toLowerCase();if(ui.hasOwnProperty(u)){n.create.push(hc,u,l,i<<17|1);const a=c.attributes;for(let e=0;e0&&o!==a){let e=o.index-Ie;yt()||(e=~e),u.push(e<<3|0)}const d=[],h=[];if(""===i&&Fc(r))u.push(i,jc(s),c<<17|1);else{const e=function(e,t){if(Fc(t))return Yc(e);{const n=e.indexOf(`:${t}\ufffd`)+2+t.toString().length,i=e.search(new RegExp(`\ufffd\\/\\*\\d+:${t}\ufffd`));return Yc(e.substring(n,i))}}(i,r),t=(f=e,f.replace(Ac," ")).split(Ec);for(let n=0;n0&&function(e,t,n){if(n>0&&e.firstCreatePass){for(let i=0;i>1),o++}})(mt(),e),ko(!1)}function Xc(e,t,n){Kc(e,t,n),Zc()}function el(e,t){const n=pt(),i=mt();!function(e,t,n,i){const r=gt().index-Ie,s=[];for(let o=0;o0){const i=e.data[n+Ie];let r,s=null;Array.isArray(i)?r=i:(r=i.update,s=i.icus),yc(e,s,t,r,xt()-gc-1,bc),bc=0,gc=0}}(mt(),pt(),e)}function il(e,t={}){return function(e,t={}){let n=e;if(Vc.test(e)){const e={},t=[0];n=n.replace(Bc,(n,i,r)=>{const s=i||r,o=e[s]||[];if(o.length||(s.split("|").forEach(e=>{const t=e.match(Qc),n=t?parseInt(t[1],10):0,i=Jc.test(e);o.push([n,i,e])}),e[s]=o),!o.length)throw new Error("i18n postprocess: unmatched placeholder - "+s);const a=t[t.length-1];let c=0;for(let e=0;et.hasOwnProperty(i)?`${n}${t[i]}${o}`:e),n=n.replace(qc,(e,n)=>t.hasOwnProperty(n)?t[n]:e),n=n.replace(Gc,(e,n)=>{if(t.hasOwnProperty(n)){const i=t[n];if(!i.length)throw new Error(`i18n postprocess: unmatched ICU - ${e} with key: ${n}`);return i.shift()}return e}),n):n}(e,t)}const rl=new Map;class sl extends ae{constructor(e,t){super(),this._parent=t,this._bootstrapComponents=[],this.injector=this,this.destroyCbs=[],this.componentFactoryResolver=new Ga(this);const n=Ae(e),i=e[W]||null;i&&dc(i),this._bootstrapComponents=un(n.bootstrap),this._r3Injector=ks(e,t,[{provide:ae,useValue:this},{provide:_a,useValue:this.componentFactoryResolver}],C(e)),this._r3Injector._resolveInjectorDefTypes(),this.instance=this.get(e)}get(e,t=As.THROW_IF_NOT_FOUND,n=m.Default){return e===As||e===ae||e===q?this:this._r3Injector.get(e,t,n)}destroy(){const e=this._r3Injector;!e.destroyed&&e.destroy(),this.destroyCbs.forEach(e=>e()),this.destroyCbs=null}onDestroy(e){this.destroyCbs.push(e)}}class ol extends ce{constructor(e){super(),this.moduleType=e,null!==Ae(e)&&function e(t){if(null!==t.\u0275mod.id){const e=t.\u0275mod.id;(function(e,t,n){if(t&&t!==n)throw new Error(`Duplicate module registered for ${e} - ${C(t)} vs ${C(t.name)}`)})(e,rl.get(e),t),rl.set(e,t)}let n=t.\u0275mod.imports;n instanceof Function&&(n=n()),n&&n.forEach(t=>e(t))}(e)}create(e){return new sl(this.moduleType,e)}}function al(e,t,n){const i=Mt()+e,r=pt();return r[i]===zi?qs(r,i,n?t.call(n):t()):Gs(r,i)}function cl(e,t,n,i){return pl(pt(),Mt(),e,t,n,i)}function ll(e,t,n,i,r){return ml(pt(),Mt(),e,t,n,i,r)}function ul(e,t,n,i,r,s){return bl(pt(),Mt(),e,t,n,i,r,s)}function dl(e,t,n,i,r,s,o){return function(e,t,n,i,r,s,o,a,c){const l=t+n;return Zs(e,l,r,s,o,a)?qs(e,l+4,c?i.call(c,r,s,o,a):i(r,s,o,a)):fl(e,l+4)}(pt(),Mt(),e,t,n,i,r,s,o)}function hl(e,t,n,i,r,s,o,a){const c=Mt()+e,l=pt(),u=Zs(l,c,n,i,r,s);return Js(l,c+4,o)||u?qs(l,c+5,a?t.call(a,n,i,r,s,o):t(n,i,r,s,o)):Gs(l,c+5)}function fl(e,t){const n=e[t];return n===zi?void 0:n}function pl(e,t,n,i,r,s){const o=t+n;return Js(e,o,r)?qs(e,o+1,s?i.call(s,r):i(r)):fl(e,o+1)}function ml(e,t,n,i,r,s,o){const a=t+n;return Qs(e,a,r,s)?qs(e,a+2,o?i.call(o,r,s):i(r,s)):fl(e,a+2)}function bl(e,t,n,i,r,s,o,a){const c=t+n;return Ks(e,c,r,s,o)?qs(e,c+3,a?i.call(a,r,s,o):i(r,s,o)):fl(e,c+3)}function gl(e,t){const n=mt();let i;const r=e+Ie;n.firstCreatePass?(i=function(e,t){if(t)for(let n=t.length-1;n>=0;n--){const i=t[n];if(e===i.name)return i}throw new Error(`The pipe '${e}' could not be found!`)}(t,n.pipeRegistry),n.data[r]=i,i.onDestroy&&(n.destroyHooks||(n.destroyHooks=[])).push(r,i.onDestroy)):i=n.data[r];const s=i.factory||(i.factory=Ee(i.type)),o=te(ro);try{const t=hn(!1),i=s();return hn(t),function(e,t,n,i){const r=n+Ie;r>=e.data.length&&(e.data[r]=null,e.blueprint[r]=null),t[r]=i}(n,pt(),e,i),i}finally{te(o)}}function _l(e,t,n){const i=pt(),r=rt(i,e);return Sl(i,wl(i,e)?pl(i,Mt(),t,r.transform,n,r):r.transform(n))}function yl(e,t,n,i){const r=pt(),s=rt(r,e);return Sl(r,wl(r,e)?ml(r,Mt(),t,s.transform,n,i,s):s.transform(n,i))}function vl(e,t,n,i,r){const s=pt(),o=rt(s,e);return Sl(s,wl(s,e)?bl(s,Mt(),t,o.transform,n,i,r,o):o.transform(n,i,r))}function wl(e,t){return e[1].data[t+Ie].pure}function Sl(e,t){return Vs.isWrapped(t)&&(t=Vs.unwrap(t),e[xt()]=zi),t}const Ml=class extends i.a{constructor(e=!1){super(),this.__isAsync=e}emit(e){super.next(e)}subscribe(e,t,n){let i,s=e=>null,o=()=>null;e&&"object"==typeof e?(i=this.__isAsync?t=>{setTimeout(()=>e.next(t))}:t=>{e.next(t)},e.error&&(s=this.__isAsync?t=>{setTimeout(()=>e.error(t))}:t=>{e.error(t)}),e.complete&&(o=this.__isAsync?()=>{setTimeout(()=>e.complete())}:()=>{e.complete()})):(i=this.__isAsync?t=>{setTimeout(()=>e(t))}:t=>{e(t)},t&&(s=this.__isAsync?e=>{setTimeout(()=>t(e))}:e=>{t(e)}),n&&(o=this.__isAsync?()=>{setTimeout(()=>n())}:()=>{n()}));const a=super.subscribe(i,s,o);return e instanceof r.a&&e.add(a),a}};function xl(){return this._results[Ws()]()}class kl{constructor(){this.dirty=!0,this._results=[],this.changes=new Ml,this.length=0;const e=Ws(),t=kl.prototype;t[e]||(t[e]=xl)}map(e){return this._results.map(e)}filter(e){return this._results.filter(e)}find(e){return this._results.find(e)}reduce(e,t){return this._results.reduce(e,t)}forEach(e){this._results.forEach(e)}some(e){return this._results.some(e)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(e){this._results=function e(t,n){void 0===n&&(n=t);for(let i=0;i0)r.push(a[t/2]);else{const s=o[t+1],a=n[-i];for(let t=Pe;t{class e{constructor(e){this.appInits=e,this.initialized=!1,this.done=!1,this.donePromise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}runInitializers(){if(this.initialized)return;const e=[],t=()=>{this.done=!0,this.resolve()};if(this.appInits)for(let n=0;n{t()}).catch(e=>{this.reject(e)}),0===e.length&&t(),this.initialized=!0}}return e.\u0275fac=function(t){return new(t||e)(ie(ql,8))},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();const Jl=new U("AppId"),Ql={provide:Jl,useFactory:function(){return`${Kl()}${Kl()}${Kl()}`},deps:[]};function Kl(){return String.fromCharCode(97+Math.floor(25*Math.random()))}const Zl=new U("Platform Initializer"),Xl=new U("Platform ID"),eu=new U("appBootstrapListener");let tu=(()=>{class e{log(e){console.log(e)}warn(e){console.warn(e)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();const nu=new U("LocaleId"),iu=new U("DefaultCurrencyCode");class ru{constructor(e,t){this.ngModuleFactory=e,this.componentFactories=t}}const su=function(e){return new ol(e)},ou=su,au=function(e){return Promise.resolve(su(e))},cu=function(e){const t=su(e),n=un(Ae(e).declarations).reduce((e,t)=>{const n=Re(t);return n&&e.push(new Ka(n)),e},[]);return new ru(t,n)},lu=cu,uu=function(e){return Promise.resolve(cu(e))};let du=(()=>{class e{constructor(){this.compileModuleSync=ou,this.compileModuleAsync=au,this.compileModuleAndAllComponentsSync=lu,this.compileModuleAndAllComponentsAsync=uu}clearCache(){}clearCacheFor(e){}getModuleId(e){}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();const hu=(()=>Promise.resolve(0))();function fu(e){"undefined"==typeof Zone?hu.then(()=>{e&&e.apply(null,null)}):Zone.current.scheduleMicroTask("scheduleMicrotask",e)}class pu{constructor({enableLongStackTrace:e=!1,shouldCoalesceEventChangeDetection:t=!1}){if(this.hasPendingMacrotasks=!1,this.hasPendingMicrotasks=!1,this.isStable=!0,this.onUnstable=new Ml(!1),this.onMicrotaskEmpty=new Ml(!1),this.onStable=new Ml(!1),this.onError=new Ml(!1),"undefined"==typeof Zone)throw new Error("In this configuration Angular requires Zone.js");Zone.assertZonePatched();const n=this;n._nesting=0,n._outer=n._inner=Zone.current,Zone.wtfZoneSpec&&(n._inner=n._inner.fork(Zone.wtfZoneSpec)),Zone.TaskTrackingZoneSpec&&(n._inner=n._inner.fork(new Zone.TaskTrackingZoneSpec)),e&&Zone.longStackTraceZoneSpec&&(n._inner=n._inner.fork(Zone.longStackTraceZoneSpec)),n.shouldCoalesceEventChangeDetection=t,n.lastRequestAnimationFrameId=-1,n.nativeRequestAnimationFrame=function(){let e=F.requestAnimationFrame,t=F.cancelAnimationFrame;if("undefined"!=typeof Zone&&e&&t){const n=e[Zone.__symbol__("OriginalDelegate")];n&&(e=n);const i=t[Zone.__symbol__("OriginalDelegate")];i&&(t=i)}return{nativeRequestAnimationFrame:e,nativeCancelAnimationFrame:t}}().nativeRequestAnimationFrame,function(e){const t=!!e.shouldCoalesceEventChangeDetection&&e.nativeRequestAnimationFrame&&(()=>{!function(e){-1===e.lastRequestAnimationFrameId&&(e.lastRequestAnimationFrameId=e.nativeRequestAnimationFrame.call(F,()=>{e.fakeTopEventTask||(e.fakeTopEventTask=Zone.root.scheduleEventTask("fakeTopEventTask",()=>{e.lastRequestAnimationFrameId=-1,_u(e),gu(e)},void 0,()=>{},()=>{})),e.fakeTopEventTask.invoke()}),_u(e))}(e)});e._inner=e._inner.fork({name:"angular",properties:{isAngularZone:!0,maybeDelayChangeDetection:t},onInvokeTask:(n,i,r,s,o,a)=>{try{return yu(e),n.invokeTask(r,s,o,a)}finally{t&&"eventTask"===s.type&&t(),vu(e)}},onInvoke:(t,n,i,r,s,o,a)=>{try{return yu(e),t.invoke(i,r,s,o,a)}finally{vu(e)}},onHasTask:(t,n,i,r)=>{t.hasTask(i,r),n===i&&("microTask"==r.change?(e._hasPendingMicrotasks=r.microTask,_u(e),gu(e)):"macroTask"==r.change&&(e.hasPendingMacrotasks=r.macroTask))},onHandleError:(t,n,i,r)=>(t.handleError(i,r),e.runOutsideAngular(()=>e.onError.emit(r)),!1)})}(n)}static isInAngularZone(){return!0===Zone.current.get("isAngularZone")}static assertInAngularZone(){if(!pu.isInAngularZone())throw new Error("Expected to be in Angular Zone, but it is not!")}static assertNotInAngularZone(){if(pu.isInAngularZone())throw new Error("Expected to not be in Angular Zone, but it is!")}run(e,t,n){return this._inner.run(e,t,n)}runTask(e,t,n,i){const r=this._inner,s=r.scheduleEventTask("NgZoneEvent: "+i,e,bu,mu,mu);try{return r.runTask(s,t,n)}finally{r.cancelTask(s)}}runGuarded(e,t,n){return this._inner.runGuarded(e,t,n)}runOutsideAngular(e){return this._outer.run(e)}}function mu(){}const bu={};function gu(e){if(0==e._nesting&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function _u(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||e.shouldCoalesceEventChangeDetection&&-1!==e.lastRequestAnimationFrameId)}function yu(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function vu(e){e._nesting--,gu(e)}class wu{constructor(){this.hasPendingMicrotasks=!1,this.hasPendingMacrotasks=!1,this.isStable=!0,this.onUnstable=new Ml,this.onMicrotaskEmpty=new Ml,this.onStable=new Ml,this.onError=new Ml}run(e,t,n){return e.apply(t,n)}runGuarded(e,t,n){return e.apply(t,n)}runOutsideAngular(e){return e()}runTask(e,t,n,i){return e.apply(t,n)}}let Su=(()=>{class e{constructor(e){this._ngZone=e,this._pendingCount=0,this._isZoneStable=!0,this._didWork=!1,this._callbacks=[],this.taskTrackingZone=null,this._watchAngularEvents(),e.run(()=>{this.taskTrackingZone="undefined"==typeof Zone?null:Zone.current.get("TaskTrackingZone")})}_watchAngularEvents(){this._ngZone.onUnstable.subscribe({next:()=>{this._didWork=!0,this._isZoneStable=!1}}),this._ngZone.runOutsideAngular(()=>{this._ngZone.onStable.subscribe({next:()=>{pu.assertNotInAngularZone(),fu(()=>{this._isZoneStable=!0,this._runCallbacksIfReady()})}})})}increasePendingRequestCount(){return this._pendingCount+=1,this._didWork=!0,this._pendingCount}decreasePendingRequestCount(){if(this._pendingCount-=1,this._pendingCount<0)throw new Error("pending async requests below zero");return this._runCallbacksIfReady(),this._pendingCount}isStable(){return this._isZoneStable&&0===this._pendingCount&&!this._ngZone.hasPendingMacrotasks}_runCallbacksIfReady(){if(this.isStable())fu(()=>{for(;0!==this._callbacks.length;){let e=this._callbacks.pop();clearTimeout(e.timeoutId),e.doneCb(this._didWork)}this._didWork=!1});else{let e=this.getPendingTasks();this._callbacks=this._callbacks.filter(t=>!t.updateCb||!t.updateCb(e)||(clearTimeout(t.timeoutId),!1)),this._didWork=!0}}getPendingTasks(){return this.taskTrackingZone?this.taskTrackingZone.macroTasks.map(e=>({source:e.source,creationLocation:e.creationLocation,data:e.data})):[]}addCallback(e,t,n){let i=-1;t&&t>0&&(i=setTimeout(()=>{this._callbacks=this._callbacks.filter(e=>e.timeoutId!==i),e(this._didWork,this.getPendingTasks())},t)),this._callbacks.push({doneCb:e,timeoutId:i,updateCb:n})}whenStable(e,t,n){if(n&&!this.taskTrackingZone)throw new Error('Task tracking zone is required when passing an update callback to whenStable(). Is "zone.js/dist/task-tracking.js" loaded?');this.addCallback(e,t,n),this._runCallbacksIfReady()}getPendingRequestCount(){return this._pendingCount}findProviders(e,t,n){return[]}}return e.\u0275fac=function(t){return new(t||e)(ie(pu))},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})(),Mu=(()=>{class e{constructor(){this._applications=new Map,Tu.addToWindow(this)}registerApplication(e,t){this._applications.set(e,t)}unregisterApplication(e){this._applications.delete(e)}unregisterAllApplications(){this._applications.clear()}getTestability(e){return this._applications.get(e)||null}getAllTestabilities(){return Array.from(this._applications.values())}getAllRootElements(){return Array.from(this._applications.keys())}findTestabilityInTree(e,t=!0){return Tu.findTestabilityInTree(this,e,t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();class xu{addToWindow(e){}findTestabilityInTree(e,t,n){return null}}function ku(e){Tu=e}let Du,Tu=new xu;const Cu=new U("AllowMultipleToken");class Ou{constructor(e,t){this.name=e,this.token=t}}function Lu(e,t,n=[]){const i="Platform: "+t,r=new U(i);return(t=[])=>{let s=Ru();if(!s||s.injector.get(Cu,!1))if(e)e(n.concat(t).concat({provide:r,useValue:!0}));else{const e=n.concat(t).concat({provide:r,useValue:!0},{provide:ys,useValue:"platform"});!function(e){if(Du&&!Du.destroyed&&!Du.injector.get(Cu,!1))throw new Error("There can be only one platform. Destroy the previous one to create a new one.");Du=e.get(Eu);const t=e.get(Zl,null);t&&t.forEach(e=>e())}(As.create({providers:e,name:i}))}return function(e){const t=Ru();if(!t)throw new Error("No platform exists!");if(!t.injector.get(e,null))throw new Error("A platform with a different configuration has been created. Please destroy it first.");return t}(r)}}function Ru(){return Du&&!Du.destroyed?Du:null}let Eu=(()=>{class e{constructor(e){this._injector=e,this._modules=[],this._destroyListeners=[],this._destroyed=!1}bootstrapModuleFactory(e,t){const n=function(e,t){let n;return n="noop"===e?new wu:("zone.js"===e?void 0:e)||new pu({enableLongStackTrace:Jn(),shouldCoalesceEventChangeDetection:t}),n}(t?t.ngZone:void 0,t&&t.ngZoneEventCoalescing||!1),i=[{provide:pu,useValue:n}];return n.run(()=>{const t=As.create({providers:i,parent:this.injector,name:e.moduleType.name}),r=e.create(t),s=r.injector.get(En,null);if(!s)throw new Error("No ErrorHandler. Is platform module (BrowserModule) included?");return r.onDestroy(()=>Pu(this._modules,r)),n.runOutsideAngular(()=>n.onError.subscribe({next:e=>{s.handleError(e)}})),function(e,t,n){try{const i=n();return bo(i)?i.catch(n=>{throw t.runOutsideAngular(()=>e.handleError(n)),n}):i}catch(i){throw t.runOutsideAngular(()=>e.handleError(i)),i}}(s,n,()=>{const e=r.injector.get(Gl);return e.runInitializers(),e.donePromise.then(()=>(dc(r.injector.get(nu,lc)||lc),this._moduleDoBootstrap(r),r))})})}bootstrapModule(e,t=[]){const n=Au({},t);return function(e,t,n){const i=new ol(n);return Promise.resolve(i)}(0,0,e).then(e=>this.bootstrapModuleFactory(e,n))}_moduleDoBootstrap(e){const t=e.injector.get(Iu);if(e._bootstrapComponents.length>0)e._bootstrapComponents.forEach(e=>t.bootstrap(e));else{if(!e.instance.ngDoBootstrap)throw new Error(`The module ${C(e.instance.constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. Please define one of these.`);e.instance.ngDoBootstrap(t)}this._modules.push(e)}onDestroy(e){this._destroyListeners.push(e)}get injector(){return this._injector}destroy(){if(this._destroyed)throw new Error("The platform has already been destroyed!");this._modules.slice().forEach(e=>e.destroy()),this._destroyListeners.forEach(e=>e()),this._destroyed=!0}get destroyed(){return this._destroyed}}return e.\u0275fac=function(t){return new(t||e)(ie(As))},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();function Au(e,t){return Array.isArray(t)?t.reduce(Au,e):Object.assign(Object.assign({},e),t)}let Iu=(()=>{class e{constructor(e,t,n,i,r,c){this._zone=e,this._console=t,this._injector=n,this._exceptionHandler=i,this._componentFactoryResolver=r,this._initStatus=c,this._bootstrapListeners=[],this._views=[],this._runningTick=!1,this._enforceNoNewChanges=!1,this._stable=!0,this.componentTypes=[],this.components=[],this._enforceNoNewChanges=Jn(),this._zone.onMicrotaskEmpty.subscribe({next:()=>{this._zone.run(()=>{this.tick()})}});const l=new s.a(e=>{this._stable=this._zone.isStable&&!this._zone.hasPendingMacrotasks&&!this._zone.hasPendingMicrotasks,this._zone.runOutsideAngular(()=>{e.next(this._stable),e.complete()})}),u=new s.a(e=>{let t;this._zone.runOutsideAngular(()=>{t=this._zone.onStable.subscribe(()=>{pu.assertNotInAngularZone(),fu(()=>{this._stable||this._zone.hasPendingMacrotasks||this._zone.hasPendingMicrotasks||(this._stable=!0,e.next(!0))})})});const n=this._zone.onUnstable.subscribe(()=>{pu.assertInAngularZone(),this._stable&&(this._stable=!1,this._zone.runOutsideAngular(()=>{e.next(!1)}))});return()=>{t.unsubscribe(),n.unsubscribe()}});this.isStable=Object(o.a)(l,u.pipe(Object(a.a)()))}bootstrap(e,t){if(!this._initStatus.done)throw new Error("Cannot bootstrap as there are still asynchronous initializers running. Bootstrap components in the `ngDoBootstrap` method of the root module.");let n;n=e instanceof ba?e:this._componentFactoryResolver.resolveComponentFactory(e),this.componentTypes.push(n.componentType);const i=n.isBoundToModule?void 0:this._injector.get(ae),r=n.create(As.NULL,[],t||n.selector,i);r.onDestroy(()=>{this._unloadComponent(r)});const s=r.injector.get(Su,null);return s&&r.injector.get(Mu).registerApplication(r.location.nativeElement,s),this._loadComponent(r),Jn()&&this._console.log("Angular is running in development mode. Call enableProdMode() to enable production mode."),r}tick(){if(this._runningTick)throw new Error("ApplicationRef.tick is called recursively");try{this._runningTick=!0;for(let e of this._views)e.detectChanges();if(this._enforceNoNewChanges)for(let e of this._views)e.checkNoChanges()}catch(e){this._zone.runOutsideAngular(()=>this._exceptionHandler.handleError(e))}finally{this._runningTick=!1}}attachView(e){const t=e;this._views.push(t),t.attachToAppRef(this)}detachView(e){const t=e;Pu(this._views,t),t.detachFromAppRef()}_loadComponent(e){this.attachView(e.hostView),this.tick(),this.components.push(e),this._injector.get(eu,[]).concat(this._bootstrapListeners).forEach(t=>t(e))}_unloadComponent(e){this.detachView(e.hostView),Pu(this.components,e)}ngOnDestroy(){this._views.slice().forEach(e=>e.destroy())}get viewCount(){return this._views.length}}return e.\u0275fac=function(t){return new(t||e)(ie(pu),ie(tu),ie(As),ie(En),ie(_a),ie(Gl))},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();function Pu(e,t){const n=e.indexOf(t);n>-1&&e.splice(n,1)}class ju{}class Nu{}const Fu={factoryPathPrefix:"",factoryPathSuffix:".ngfactory"};let Yu=(()=>{class e{constructor(e,t){this._compiler=e,this._config=t||Fu}load(e){return this.loadAndCompile(e)}loadAndCompile(e){let[t,i]=e.split("#");return void 0===i&&(i="default"),n("zn8P")(t).then(e=>e[i]).then(e=>zu(e,t,i)).then(e=>this._compiler.compileModuleAsync(e))}loadFactory(e){let[t,i]=e.split("#"),r="NgFactory";return void 0===i&&(i="default",r=""),n("zn8P")(this._config.factoryPathPrefix+t+this._config.factoryPathSuffix).then(e=>e[i+r]).then(e=>zu(e,t,i))}}return e.\u0275fac=function(t){return new(t||e)(ie(du),ie(Nu,8))},e.\u0275prov=_({token:e,factory:e.\u0275fac}),e})();function zu(e,t,n){if(!e)throw new Error(`Cannot find '${n}' in '${t}'`);return e}const $u=function(e){return null},Hu=Lu(null,"core",[{provide:Xl,useValue:"unknown"},{provide:Eu,deps:[As]},{provide:Mu,deps:[]},{provide:tu,deps:[]}]),Wu=[{provide:Iu,useClass:Iu,deps:[pu,tu,As,En,_a,Gl]},{provide:Qa,deps:[pu],useFactory:function(e){let t=[];return e.onStable.subscribe(()=>{for(;t.length;)t.pop()()}),function(e){t.push(e)}}},{provide:Gl,useClass:Gl,deps:[[new h,ql]]},{provide:du,useClass:du,deps:[]},Ql,{provide:Fa,useFactory:function(){return $a},deps:[]},{provide:Ya,useFactory:function(){return Ha},deps:[]},{provide:nu,useFactory:function(e){return dc(e=e||"undefined"!=typeof $localize&&$localize.locale||lc),e},deps:[[new d(nu),new h,new p]]},{provide:iu,useValue:"USD"}];let Vu=(()=>{class e{constructor(e){}}return e.\u0275mod=De({type:e}),e.\u0275inj=y({factory:function(t){return new(t||e)(ie(Iu))},providers:Wu}),e})()},"8YOa":function(e,t,n){var i=n("0BK2"),r=n("hh1v"),s=n("UTVS"),o=n("m/L8").f,a=n("kOOl"),c=n("uy83"),l=a("meta"),u=0,d=Object.isExtensible||function(){return!0},h=function(e){o(e,l,{value:{objectID:"O"+ ++u,weakData:{}}})},f=e.exports={REQUIRED:!1,fastKey:function(e,t){if(!r(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!s(e,l)){if(!d(e))return"F";if(!t)return"E";h(e)}return e[l].objectID},getWeakData:function(e,t){if(!s(e,l)){if(!d(e))return!0;if(!t)return!1;h(e)}return e[l].weakData},onFreeze:function(e){return c&&f.REQUIRED&&d(e)&&!s(e,l)&&h(e),e}};i[l]=!0},"8mBD":function(e,t,n){!function(e){"use strict";e.defineLocale("pt",{months:"janeiro_fevereiro_mar\xe7o_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"Domingo_Segunda-feira_Ter\xe7a-feira_Quarta-feira_Quinta-feira_Sexta-feira_S\xe1bado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_S\xe1b".split("_"),weekdaysMin:"Do_2\xaa_3\xaa_4\xaa_5\xaa_6\xaa_S\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje \xe0s] LT",nextDay:"[Amanh\xe3 \xe0s] LT",nextWeek:"dddd [\xe0s] LT",lastDay:"[Ontem \xe0s] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[\xdaltimo] dddd [\xe0s] LT":"[\xdaltima] dddd [\xe0s] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"h\xe1 %s",s:"segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",w:"uma semana",ww:"%d semanas",M:"um m\xeas",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:1,doy:4}})}(n("wd/R"))},"8xTl":function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");let o=(()=>{class e{transform(e){return r.a.upperFirst(e)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=s.Lb({name:"upperFirst",type:e,pure:!0}),e})()},"9/5/":function(e,t){var n=/^\s+|\s+$/g,i=/^[-+]0x[0-9a-f]+$/i,r=/^0b[01]+$/i,s=/^0o[0-7]+$/i,o=parseInt,a="object"==typeof global&&global&&global.Object===Object&&global,c="object"==typeof self&&self&&self.Object===Object&&self,l=a||c||Function("return this")(),u=Object.prototype.toString,d=Math.max,h=Math.min,f=function(){return l.Date.now()};function p(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function m(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==u.call(e)}(e))return NaN;if(p(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=p(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(n,"");var a=r.test(e);return a||s.test(e)?o(e.slice(2),a?2:8):i.test(e)?NaN:+e}e.exports=function(e,t,n){var i,r,s,o,a,c,l=0,u=!1,b=!1,g=!0;if("function"!=typeof e)throw new TypeError("Expected a function");function _(t){var n=i,s=r;return i=r=void 0,l=t,o=e.apply(s,n)}function y(e){return l=e,a=setTimeout(w,t),u?_(e):o}function v(e){var n=e-c;return void 0===c||n>=t||n<0||b&&e-l>=s}function w(){var e=f();if(v(e))return S(e);a=setTimeout(w,function(e){var n=t-(e-c);return b?h(n,s-(e-l)):n}(e))}function S(e){return a=void 0,g&&i?_(e):(i=r=void 0,o)}function M(){var e=f(),n=v(e);if(i=arguments,r=this,c=e,n){if(void 0===a)return y(c);if(b)return a=setTimeout(w,t),_(c)}return void 0===a&&(a=setTimeout(w,t)),o}return t=m(t)||0,p(n)&&(u=!!n.leading,s=(b="maxWait"in n)?d(m(n.maxWait)||0,t):s,g="trailing"in n?!!n.trailing:g),M.cancel=function(){void 0!==a&&clearTimeout(a),l=0,i=c=r=a=void 0},M.flush=function(){return void 0===a?o:S(f())},M}},"93I0":function(e,t,n){var i=n("VpIT"),r=n("kOOl"),s=i("keys");e.exports=function(e){return s[e]||(s[e]=r(e))}},"9Xeq":function(e,t,n){"use strict";n.d(t,"a",(function(){return T}));var i=n("SVse"),r=n("yT6U"),s=n("iExv"),o=n("4DD9"),a=n("a0VL"),c=n("+0ag"),l=n("85J/"),u=n("IzCI"),d=n("Fgil"),h=n("o4+5"),f=n("nSDx"),p=n("8Y7J");let m=(()=>{class e{transform(e){return encodeURIComponent(e)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=p.Lb({name:"encodeUri",type:e,pure:!0}),e})();var b=n("BQkM"),g=n("uYzU"),_=n("FFMq"),y=n("E2fk"),v=n("TJUb"),w=n("dEH0"),S=n("G1/K"),M=n("TYzs"),x=n("Dwqy"),k=n("efK2"),D=n("8xTl");let T=(()=>{class e{}return e.\u0275mod=p.Kb({type:e}),e.\u0275inj=p.Jb({factory:function(t){return new(t||e)},providers:[r.a,o.a,s.a,i.e,l.a,c.a,d.a,u.a,h.a,x.a,g.a,_.a,y.a,a.a,f.a,m,M.a,b.a,w.a,S.a,D.a,v.a,k.a],imports:[[i.c]]}),e})()},"9d/t":function(e,t,n){var i=n("AO7/"),r=n("xrYK"),s=n("tiKp")("toStringTag"),o="Arguments"==r(function(){return arguments}());e.exports=i?r:function(e){var t,n,i;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(n){}}(t=Object(e),s))?n:o?r(t):"Object"==(i=r(t))&&"function"==typeof t.callee?"Arguments":i}},"9f76":function(e,t,n){"use strict";var i=n("8M4i"),r=n("EUcb"),s=function(e){return Object(r.a)(e)&&"[object Arguments]"==Object(i.a)(e)},o=Object.prototype,a=o.hasOwnProperty,c=o.propertyIsEnumerable,l=s(function(){return arguments}())?s:function(e){return Object(r.a)(e)&&a.call(e,"callee")&&!c.call(e,"callee")};t.a=l},"9nlD":function(e,t,n){"use strict";n.d(t,"a",(function(){return f}));var i=n("LvDl"),r=n.n(i),s=n("2Vo4"),o=n("XNiG"),a=n("mtw6"),c=n("G1I9"),l=n("a0VL"),u=n("ufoC"),d=n("8Y7J"),h=n("EApP");let f=(()=>{class e{constructor(e,t,n){this.toastr=e,this.taskMessageService=t,this.cdDatePipe=n,this.hideToasties=!1,this.dataSource=new s.a([]),this.data$=this.dataSource.asObservable(),this.sidebarSubject=new o.a,this.queued=[],this.KEY="cdNotifications";const i=localStorage.getItem(this.KEY);let a=[];r.a.isString(i)&&(a=JSON.parse(i,(e,t)=>r.a.isPlainObject(t)?r.a.assign(new c.a,t):t)),this.dataSource.next(a)}removeAll(){localStorage.removeItem(this.KEY),this.dataSource.next([])}remove(e){const t=this.dataSource.getValue();t.splice(e,1),this.dataSource.next(t),localStorage.setItem(this.KEY,JSON.stringify(t))}save(e){const t=this.dataSource.getValue();for(t.push(e),t.sort((e,t)=>e.timestamp>t.timestamp?-1:1);t.length>10;)t.pop();this.dataSource.next(t),localStorage.setItem(this.KEY,JSON.stringify(t))}show(e,t,n,i,s){return window.setTimeout(()=>{let o;o=r.a.isFunction(e)?e():r.a.isObject(e)?e:new c.b(e,t,n,i,s),this.queueToShow(o)},10)}queueToShow(e){this.cancel(this.queuedTimeoutId),this.queued.find(t=>r.a.isEqual(t,e))||this.queued.push(e),this.queuedTimeoutId=window.setTimeout(()=>{this.showQueued()},500)}showQueued(){this.getUnifiedTitleQueue().forEach(e=>{const t=new c.a(e);t.isFinishedTask||this.save(t),this.showToasty(t)})}getUnifiedTitleQueue(){return Object.values(this.queueShiftByTitle()).map(e=>{const t=e[0];return e.length>1&&(t.message="
    "+e.map(e=>`
  • ${e.message}
  • `).join("")+"
"),t})}queueShiftByTitle(){const e={};let t;for(;t=this.queued.shift();)e[t.title]||(e[t.title]=[]),e[t.title].push(t);return e}showToasty(e){this.hideToasties||this.toastr[["error","info","success"][e.type]]((e.message?e.message+"
":"")+this.renderTimeAndApplicationHtml(e),e.title,e.options)}renderTimeAndApplicationHtml(e){return`${this.cdDatePipe.transform(e.timestamp)}`}notifyTask(e,t=!0){const n=this.finishedTaskToNotification(e,t);return n.isFinishedTask=!0,this.show(n)}finishedTaskToNotification(e,t=!0){let n;return n=e.success&&t?new c.b(a.a.success,this.taskMessageService.getSuccessTitle(e)):new c.b(a.a.error,this.taskMessageService.getErrorTitle(e),this.taskMessageService.getErrorMessage(e)),n.isFinishedTask=!0,n}cancel(e){window.clearTimeout(e)}suspendToasties(e){this.hideToasties=e}toggleSidebar(e=!1){this.sidebarSubject.next(e)}}return e.\u0275fac=function(t){return new(t||e)(d.dc(h.b),d.dc(u.a),d.dc(l.a))},e.\u0275prov=d.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},"9ppp":function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));const i=(()=>{function e(){return Error.call(this),this.message="object unsubscribed",this.name="ObjectUnsubscribedError",this}return e.prototype=Object.create(Error.prototype),e})()},"9rRi":function(e,t,n){!function(e){"use strict";e.defineLocale("gd",{months:["Am Faoilleach","An Gearran","Am M\xe0rt","An Giblean","An C\xe8itean","An t-\xd2gmhios","An t-Iuchar","An L\xf9nastal","An t-Sultain","An D\xe0mhair","An t-Samhain","An D\xf9bhlachd"],monthsShort:["Faoi","Gear","M\xe0rt","Gibl","C\xe8it","\xd2gmh","Iuch","L\xf9n","Sult","D\xe0mh","Samh","D\xf9bh"],monthsParseExact:!0,weekdays:["Did\xf2mhnaich","Diluain","Dim\xe0irt","Diciadain","Diardaoin","Dihaoine","Disathairne"],weekdaysShort:["Did","Dil","Dim","Dic","Dia","Dih","Dis"],weekdaysMin:["D\xf2","Lu","M\xe0","Ci","Ar","Ha","Sa"],longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-m\xe0ireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-d\xe8 aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",ss:"%d diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"m\xecos",MM:"%d m\xecosan",y:"bliadhna",yy:"%d bliadhna"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(n("wd/R"))},"9xzX":function(e,t,n){"use strict";n.d(t,"a",(function(){return y}));var i=n("mrSG"),r=n("IheW"),s=n("LvDl"),o=n.n(s),a=n("2Vo4"),c=n("z6cu"),l=n("LRne"),u=n("vkgz"),d=n("5+tZ"),h=n("XNiG"),f=n("zx2A");class p{constructor(e,t){this.notifier=e,this.source=t}call(e,t){return t.subscribe(new m(e,this.notifier,this.source))}}class m extends f.b{constructor(e,t,n){super(e),this.notifier=t,this.source=n}error(e){if(!this.isStopped){let n=this.errors,i=this.retries,r=this.retriesSubscription;if(i)this.errors=void 0,this.retriesSubscription=void 0;else{n=new h.a;try{const{notifier:e}=this;i=e(n)}catch(t){return super.error(t)}r=Object(f.c)(i,new f.a(this))}this._unsubscribeAndRecycle(),this.errors=n,this.retries=i,this.retriesSubscription=r,n.next(e)}}_unsubscribe(){const{errors:e,retriesSubscription:t}=this;e&&(e.unsubscribe(),this.errors=void 0),t&&(t.unsubscribe(),this.retriesSubscription=void 0),this.retries=void 0}notifyNext(){const{_unsubscribe:e}=this;this._unsubscribe=null,this._unsubscribeAndRecycle(),this._unsubscribe=e,this.source.subscribe(this)}}var b=n("IzEk"),g=n("xTzq"),_=n("8Y7J");let y=(()=>{let e=class{constructor(e){this.http=e,this.url="api/rgw/daemon",this.daemons=new a.a([]),this.daemons$=this.daemons.asObservable(),this.selectedDaemon=new a.a(null),this.selectedDaemon$=this.selectedDaemon.asObservable()}list(){return this.http.get(this.url).pipe(Object(u.a)(e=>{this.daemons.next(e),o.a.isEmpty(this.selectedDaemon.getValue())&&this.selectDefaultDaemon(e)}))}get(e){return this.http.get(`${this.url}/${e}`)}selectDaemon(e){this.selectedDaemon.next(e)}selectDefaultDaemon(e){if(0===e.length)return null;for(const t of e)if(t.default)return this.selectDaemon(t),t;return this.selectDaemon(e[0]),e[0]}request(e){return this.selectedDaemon.pipe(Object(d.a)(e=>o.a.isEmpty(e)?this.list().pipe(Object(d.a)(e=>Object(c.a)(!o.a.isEmpty(e)))):Object(l.a)(e)),(t=e=>e.pipe(Object(d.a)(t=>t?e:Object(c.a)("No RGW daemons found!"))),e=>e.lift(new p(t,e))),Object(b.a)(1),Object(d.a)(t=>{let n=new r.e;return n=n.append("daemon_name",t.id),e(n)}));var t}};return e.\u0275fac=function(t){return new(t||e)(_.dc(r.b))},e.\u0275prov=_.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e=Object(i.b)([g.a,Object(i.d)("design:paramtypes",[r.b])],e),e})()},"A+xa":function(e,t,n){!function(e){"use strict";e.defineLocale("cv",{months:"\u043a\u04d1\u0440\u043b\u0430\u0447_\u043d\u0430\u0440\u04d1\u0441_\u043f\u0443\u0448_\u0430\u043a\u0430_\u043c\u0430\u0439_\u04ab\u04d7\u0440\u0442\u043c\u0435_\u0443\u0442\u04d1_\u04ab\u0443\u0440\u043b\u0430_\u0430\u0432\u04d1\u043d_\u044e\u043f\u0430_\u0447\u04f3\u043a_\u0440\u0430\u0448\u0442\u0430\u0432".split("_"),monthsShort:"\u043a\u04d1\u0440_\u043d\u0430\u0440_\u043f\u0443\u0448_\u0430\u043a\u0430_\u043c\u0430\u0439_\u04ab\u04d7\u0440_\u0443\u0442\u04d1_\u04ab\u0443\u0440_\u0430\u0432\u043d_\u044e\u043f\u0430_\u0447\u04f3\u043a_\u0440\u0430\u0448".split("_"),weekdays:"\u0432\u044b\u0440\u0441\u0430\u0440\u043d\u0438\u043a\u0443\u043d_\u0442\u0443\u043d\u0442\u0438\u043a\u0443\u043d_\u044b\u0442\u043b\u0430\u0440\u0438\u043a\u0443\u043d_\u044e\u043d\u043a\u0443\u043d_\u043a\u04d7\u04ab\u043d\u0435\u0440\u043d\u0438\u043a\u0443\u043d_\u044d\u0440\u043d\u0435\u043a\u0443\u043d_\u0448\u04d1\u043c\u0430\u0442\u043a\u0443\u043d".split("_"),weekdaysShort:"\u0432\u044b\u0440_\u0442\u0443\u043d_\u044b\u0442\u043b_\u044e\u043d_\u043a\u04d7\u04ab_\u044d\u0440\u043d_\u0448\u04d1\u043c".split("_"),weekdaysMin:"\u0432\u0440_\u0442\u043d_\u044b\u0442_\u044e\u043d_\u043a\u04ab_\u044d\u0440_\u0448\u043c".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [\u04ab\u0443\u043b\u0445\u0438] MMMM [\u0443\u0439\u04d1\u0445\u04d7\u043d] D[-\u043c\u04d7\u0448\u04d7]",LLL:"YYYY [\u04ab\u0443\u043b\u0445\u0438] MMMM [\u0443\u0439\u04d1\u0445\u04d7\u043d] D[-\u043c\u04d7\u0448\u04d7], HH:mm",LLLL:"dddd, YYYY [\u04ab\u0443\u043b\u0445\u0438] MMMM [\u0443\u0439\u04d1\u0445\u04d7\u043d] D[-\u043c\u04d7\u0448\u04d7], HH:mm"},calendar:{sameDay:"[\u041f\u0430\u044f\u043d] LT [\u0441\u0435\u0445\u0435\u0442\u0440\u0435]",nextDay:"[\u042b\u0440\u0430\u043d] LT [\u0441\u0435\u0445\u0435\u0442\u0440\u0435]",lastDay:"[\u04d6\u043d\u0435\u0440] LT [\u0441\u0435\u0445\u0435\u0442\u0440\u0435]",nextWeek:"[\u04aa\u0438\u0442\u0435\u0441] dddd LT [\u0441\u0435\u0445\u0435\u0442\u0440\u0435]",lastWeek:"[\u0418\u0440\u0442\u043d\u04d7] dddd LT [\u0441\u0435\u0445\u0435\u0442\u0440\u0435]",sameElse:"L"},relativeTime:{future:function(e){return e+(/\u0441\u0435\u0445\u0435\u0442$/i.exec(e)?"\u0440\u0435\u043d":/\u04ab\u0443\u043b$/i.exec(e)?"\u0442\u0430\u043d":"\u0440\u0430\u043d")},past:"%s \u043a\u0430\u044f\u043b\u043b\u0430",s:"\u043f\u04d7\u0440-\u0438\u043a \u04ab\u0435\u043a\u043a\u0443\u043d\u0442",ss:"%d \u04ab\u0435\u043a\u043a\u0443\u043d\u0442",m:"\u043f\u04d7\u0440 \u043c\u0438\u043d\u0443\u0442",mm:"%d \u043c\u0438\u043d\u0443\u0442",h:"\u043f\u04d7\u0440 \u0441\u0435\u0445\u0435\u0442",hh:"%d \u0441\u0435\u0445\u0435\u0442",d:"\u043f\u04d7\u0440 \u043a\u0443\u043d",dd:"%d \u043a\u0443\u043d",M:"\u043f\u04d7\u0440 \u0443\u0439\u04d1\u0445",MM:"%d \u0443\u0439\u04d1\u0445",y:"\u043f\u04d7\u0440 \u04ab\u0443\u043b",yy:"%d \u04ab\u0443\u043b"},dayOfMonthOrdinalParse:/\d{1,2}-\u043c\u04d7\u0448/,ordinal:"%d-\u043c\u04d7\u0448",week:{dow:1,doy:7}})}(n("wd/R"))},A2ZE:function(e,t,n){var i=n("HAuM");e.exports=function(e,t,n){if(i(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,i){return e.call(t,n,i)};case 3:return function(n,i,r){return e.call(t,n,i,r)}}return function(){return e.apply(t,arguments)}}},ANnk:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("aexS"),r=n("f/UV"),s=n("8Y7J");let o=(()=>{class e{constructor(e,t,n){this.formScope=e,this.authStorageService=t,this.elementRef=n}ngAfterViewInit(){var e,t,n;this.permissions=this.authStorageService.getPermissions();const i=null===(e=this.formScope)||void 0===e?void 0:e.cdFormScope;i&&!(null===(n=null===(t=this.permissions)||void 0===t?void 0:t[i])||void 0===n?void 0:n.update)&&(this.elementRef.nativeElement.disabled=!0)}}return e.\u0275fac=function(t){return new(t||e)(s.Mb(r.a,8),s.Mb(i.a),s.Mb(s.m))},e.\u0275dir=s.Hb({type:e,selectors:[["input",3,"cdNoFormInputDisable",""],["select",3,"cdNoFormInputDisable",""],["button",3,"cdNoFormInputDisable",""],["","cdFormInputDisable",""]]}),e})()},"AO7/":function(e,t,n){var i={};i[n("tiKp")("toStringTag")]="z",e.exports="[object z]"===String(i)},AQ68:function(e,t,n){!function(e){"use strict";e.defineLocale("uz-latn",{months:"Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr".split("_"),monthsShort:"Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek".split("_"),weekdays:"Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba".split("_"),weekdaysShort:"Yak_Dush_Sesh_Chor_Pay_Jum_Shan".split("_"),weekdaysMin:"Ya_Du_Se_Cho_Pa_Ju_Sha".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Bugun soat] LT [da]",nextDay:"[Ertaga] LT [da]",nextWeek:"dddd [kuni soat] LT [da]",lastDay:"[Kecha soat] LT [da]",lastWeek:"[O'tgan] dddd [kuni soat] LT [da]",sameElse:"L"},relativeTime:{future:"Yaqin %s ichida",past:"Bir necha %s oldin",s:"soniya",ss:"%d soniya",m:"bir daqiqa",mm:"%d daqiqa",h:"bir soat",hh:"%d soat",d:"bir kun",dd:"%d kun",M:"bir oy",MM:"%d oy",y:"bir yil",yy:"%d yil"},week:{dow:1,doy:7}})}(n("wd/R"))},Avrn:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("aexS"),r=n("8Y7J"),s=n("iInd");let o=(()=>{class e{constructor(e,t){this.router=e,this.authStorageService=t}canActivate(e,t){return!!this.authStorageService.isLoggedIn()||(this.router.navigate(["/login"],{queryParams:{returnUrl:t.url}}),!1)}canActivateChild(e,t){return this.canActivate(e,t)}}return e.\u0275fac=function(t){return new(t||e)(r.dc(s.e),r.dc(i.a))},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},AvvY:function(e,t,n){!function(e){"use strict";e.defineLocale("ml",{months:"\u0d1c\u0d28\u0d41\u0d35\u0d30\u0d3f_\u0d2b\u0d46\u0d2c\u0d4d\u0d30\u0d41\u0d35\u0d30\u0d3f_\u0d2e\u0d3e\u0d7c\u0d1a\u0d4d\u0d1a\u0d4d_\u0d0f\u0d2a\u0d4d\u0d30\u0d3f\u0d7d_\u0d2e\u0d47\u0d2f\u0d4d_\u0d1c\u0d42\u0d7a_\u0d1c\u0d42\u0d32\u0d48_\u0d13\u0d17\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d_\u0d38\u0d46\u0d2a\u0d4d\u0d31\u0d4d\u0d31\u0d02\u0d2c\u0d7c_\u0d12\u0d15\u0d4d\u0d1f\u0d4b\u0d2c\u0d7c_\u0d28\u0d35\u0d02\u0d2c\u0d7c_\u0d21\u0d3f\u0d38\u0d02\u0d2c\u0d7c".split("_"),monthsShort:"\u0d1c\u0d28\u0d41._\u0d2b\u0d46\u0d2c\u0d4d\u0d30\u0d41._\u0d2e\u0d3e\u0d7c._\u0d0f\u0d2a\u0d4d\u0d30\u0d3f._\u0d2e\u0d47\u0d2f\u0d4d_\u0d1c\u0d42\u0d7a_\u0d1c\u0d42\u0d32\u0d48._\u0d13\u0d17._\u0d38\u0d46\u0d2a\u0d4d\u0d31\u0d4d\u0d31._\u0d12\u0d15\u0d4d\u0d1f\u0d4b._\u0d28\u0d35\u0d02._\u0d21\u0d3f\u0d38\u0d02.".split("_"),monthsParseExact:!0,weekdays:"\u0d1e\u0d3e\u0d2f\u0d31\u0d3e\u0d34\u0d4d\u0d1a_\u0d24\u0d3f\u0d19\u0d4d\u0d15\u0d33\u0d3e\u0d34\u0d4d\u0d1a_\u0d1a\u0d4a\u0d35\u0d4d\u0d35\u0d3e\u0d34\u0d4d\u0d1a_\u0d2c\u0d41\u0d27\u0d28\u0d3e\u0d34\u0d4d\u0d1a_\u0d35\u0d4d\u0d2f\u0d3e\u0d34\u0d3e\u0d34\u0d4d\u0d1a_\u0d35\u0d46\u0d33\u0d4d\u0d33\u0d3f\u0d2f\u0d3e\u0d34\u0d4d\u0d1a_\u0d36\u0d28\u0d3f\u0d2f\u0d3e\u0d34\u0d4d\u0d1a".split("_"),weekdaysShort:"\u0d1e\u0d3e\u0d2f\u0d7c_\u0d24\u0d3f\u0d19\u0d4d\u0d15\u0d7e_\u0d1a\u0d4a\u0d35\u0d4d\u0d35_\u0d2c\u0d41\u0d27\u0d7b_\u0d35\u0d4d\u0d2f\u0d3e\u0d34\u0d02_\u0d35\u0d46\u0d33\u0d4d\u0d33\u0d3f_\u0d36\u0d28\u0d3f".split("_"),weekdaysMin:"\u0d1e\u0d3e_\u0d24\u0d3f_\u0d1a\u0d4a_\u0d2c\u0d41_\u0d35\u0d4d\u0d2f\u0d3e_\u0d35\u0d46_\u0d36".split("_"),longDateFormat:{LT:"A h:mm -\u0d28\u0d41",LTS:"A h:mm:ss -\u0d28\u0d41",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -\u0d28\u0d41",LLLL:"dddd, D MMMM YYYY, A h:mm -\u0d28\u0d41"},calendar:{sameDay:"[\u0d07\u0d28\u0d4d\u0d28\u0d4d] LT",nextDay:"[\u0d28\u0d3e\u0d33\u0d46] LT",nextWeek:"dddd, LT",lastDay:"[\u0d07\u0d28\u0d4d\u0d28\u0d32\u0d46] LT",lastWeek:"[\u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d4d",past:"%s \u0d2e\u0d41\u0d7b\u0d2a\u0d4d",s:"\u0d05\u0d7d\u0d2a \u0d28\u0d3f\u0d2e\u0d3f\u0d37\u0d19\u0d4d\u0d19\u0d7e",ss:"%d \u0d38\u0d46\u0d15\u0d4d\u0d15\u0d7b\u0d21\u0d4d",m:"\u0d12\u0d30\u0d41 \u0d2e\u0d3f\u0d28\u0d3f\u0d31\u0d4d\u0d31\u0d4d",mm:"%d \u0d2e\u0d3f\u0d28\u0d3f\u0d31\u0d4d\u0d31\u0d4d",h:"\u0d12\u0d30\u0d41 \u0d2e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d42\u0d7c",hh:"%d \u0d2e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d42\u0d7c",d:"\u0d12\u0d30\u0d41 \u0d26\u0d3f\u0d35\u0d38\u0d02",dd:"%d \u0d26\u0d3f\u0d35\u0d38\u0d02",M:"\u0d12\u0d30\u0d41 \u0d2e\u0d3e\u0d38\u0d02",MM:"%d \u0d2e\u0d3e\u0d38\u0d02",y:"\u0d12\u0d30\u0d41 \u0d35\u0d7c\u0d37\u0d02",yy:"%d \u0d35\u0d7c\u0d37\u0d02"},meridiemParse:/\u0d30\u0d3e\u0d24\u0d4d\u0d30\u0d3f|\u0d30\u0d3e\u0d35\u0d3f\u0d32\u0d46|\u0d09\u0d1a\u0d4d\u0d1a \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d4d|\u0d35\u0d48\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d47\u0d30\u0d02|\u0d30\u0d3e\u0d24\u0d4d\u0d30\u0d3f/i,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0d30\u0d3e\u0d24\u0d4d\u0d30\u0d3f"===t&&e>=4||"\u0d09\u0d1a\u0d4d\u0d1a \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d4d"===t||"\u0d35\u0d48\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d47\u0d30\u0d02"===t?e+12:e},meridiem:function(e,t,n){return e<4?"\u0d30\u0d3e\u0d24\u0d4d\u0d30\u0d3f":e<12?"\u0d30\u0d3e\u0d35\u0d3f\u0d32\u0d46":e<17?"\u0d09\u0d1a\u0d4d\u0d1a \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d4d":e<20?"\u0d35\u0d48\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d47\u0d30\u0d02":"\u0d30\u0d3e\u0d24\u0d4d\u0d30\u0d3f"}})}(n("wd/R"))},AwXo:function(e,t,n){"use strict";var i=n("Y7yP"),r=function(){try{var e=Object(i.a)(Object,"defineProperty");return e({},"",{}),e}catch(t){}}();t.a=r},AxL3:function(e,t){var n=!("undefined"==typeof window||!window.document||!window.document.createElement);e.exports=n},AytR:function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));const i={default_lang:"en-US",production:!0,year:"2021"}},B55N:function(e,t,n){!function(e){"use strict";e.defineLocale("ja",{eras:[{since:"2019-05-01",offset:1,name:"\u4ee4\u548c",narrow:"\u32ff",abbr:"R"},{since:"1989-01-08",until:"2019-04-30",offset:1,name:"\u5e73\u6210",narrow:"\u337b",abbr:"H"},{since:"1926-12-25",until:"1989-01-07",offset:1,name:"\u662d\u548c",narrow:"\u337c",abbr:"S"},{since:"1912-07-30",until:"1926-12-24",offset:1,name:"\u5927\u6b63",narrow:"\u337d",abbr:"T"},{since:"1873-01-01",until:"1912-07-29",offset:6,name:"\u660e\u6cbb",narrow:"\u337e",abbr:"M"},{since:"0001-01-01",until:"1873-12-31",offset:1,name:"\u897f\u66a6",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"\u7d00\u5143\u524d",narrow:"BC",abbr:"BC"}],eraYearOrdinalRegex:/(\u5143|\d+)\u5e74/,eraYearOrdinalParse:function(e,t){return"\u5143"===t[1]?1:parseInt(t[1]||e,10)},months:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),monthsShort:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),weekdays:"\u65e5\u66dc\u65e5_\u6708\u66dc\u65e5_\u706b\u66dc\u65e5_\u6c34\u66dc\u65e5_\u6728\u66dc\u65e5_\u91d1\u66dc\u65e5_\u571f\u66dc\u65e5".split("_"),weekdaysShort:"\u65e5_\u6708_\u706b_\u6c34_\u6728_\u91d1_\u571f".split("_"),weekdaysMin:"\u65e5_\u6708_\u706b_\u6c34_\u6728_\u91d1_\u571f".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY\u5e74M\u6708D\u65e5",LLL:"YYYY\u5e74M\u6708D\u65e5 HH:mm",LLLL:"YYYY\u5e74M\u6708D\u65e5 dddd HH:mm",l:"YYYY/MM/DD",ll:"YYYY\u5e74M\u6708D\u65e5",lll:"YYYY\u5e74M\u6708D\u65e5 HH:mm",llll:"YYYY\u5e74M\u6708D\u65e5(ddd) HH:mm"},meridiemParse:/\u5348\u524d|\u5348\u5f8c/i,isPM:function(e){return"\u5348\u5f8c"===e},meridiem:function(e,t,n){return e<12?"\u5348\u524d":"\u5348\u5f8c"},calendar:{sameDay:"[\u4eca\u65e5] LT",nextDay:"[\u660e\u65e5] LT",nextWeek:function(e){return e.week()!==this.week()?"[\u6765\u9031]dddd LT":"dddd LT"},lastDay:"[\u6628\u65e5] LT",lastWeek:function(e){return this.week()!==e.week()?"[\u5148\u9031]dddd LT":"dddd LT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}\u65e5/,ordinal:function(e,t){switch(t){case"y":return 1===e?"\u5143\u5e74":e+"\u5e74";case"d":case"D":case"DDD":return e+"\u65e5";default:return e}},relativeTime:{future:"%s\u5f8c",past:"%s\u524d",s:"\u6570\u79d2",ss:"%d\u79d2",m:"1\u5206",mm:"%d\u5206",h:"1\u6642\u9593",hh:"%d\u6642\u9593",d:"1\u65e5",dd:"%d\u65e5",M:"1\u30f6\u6708",MM:"%d\u30f6\u6708",y:"1\u5e74",yy:"%d\u5e74"}})}(n("wd/R"))},BFxc:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("7o/Q"),r=n("4I5i"),s=n("EY2u");function o(e){return function(t){return 0===e?Object(s.b)():t.lift(new a(e))}}class a{constructor(e){if(this.total=e,this.total<0)throw new r.a}call(e,t){return t.subscribe(new c(e,this.total))}}class c extends i.a{constructor(e,t){super(e),this.total=t,this.ring=new Array,this.count=0}_next(e){const t=this.ring,n=this.total,i=this.count++;t.length0){const n=this.count>=this.total?this.total:this.count,i=this.ring;for(let r=0;r{class e{transform(e){return e+" IOPS"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"iops",type:e,pure:!0}),e})()},BVg3:function(e,t,n){!function(e){"use strict";function t(e){return e%100==11||e%10!=1}function n(e,n,i,r){var s=e+" ";switch(i){case"s":return n||r?"nokkrar sek\xfandur":"nokkrum sek\xfandum";case"ss":return t(e)?s+(n||r?"sek\xfandur":"sek\xfandum"):s+"sek\xfanda";case"m":return n?"m\xedn\xfata":"m\xedn\xfatu";case"mm":return t(e)?s+(n||r?"m\xedn\xfatur":"m\xedn\xfatum"):n?s+"m\xedn\xfata":s+"m\xedn\xfatu";case"hh":return t(e)?s+(n||r?"klukkustundir":"klukkustundum"):s+"klukkustund";case"d":return n?"dagur":r?"dag":"degi";case"dd":return t(e)?n?s+"dagar":s+(r?"daga":"d\xf6gum"):n?s+"dagur":s+(r?"dag":"degi");case"M":return n?"m\xe1nu\xf0ur":r?"m\xe1nu\xf0":"m\xe1nu\xf0i";case"MM":return t(e)?n?s+"m\xe1nu\xf0ir":s+(r?"m\xe1nu\xf0i":"m\xe1nu\xf0um"):n?s+"m\xe1nu\xf0ur":s+(r?"m\xe1nu\xf0":"m\xe1nu\xf0i");case"y":return n||r?"\xe1r":"\xe1ri";case"yy":return t(e)?s+(n||r?"\xe1r":"\xe1rum"):s+(n||r?"\xe1r":"\xe1ri")}}e.defineLocale("is",{months:"jan\xfaar_febr\xfaar_mars_apr\xedl_ma\xed_j\xfan\xed_j\xfal\xed_\xe1g\xfast_september_okt\xf3ber_n\xf3vember_desember".split("_"),monthsShort:"jan_feb_mar_apr_ma\xed_j\xfan_j\xfal_\xe1g\xfa_sep_okt_n\xf3v_des".split("_"),weekdays:"sunnudagur_m\xe1nudagur_\xferi\xf0judagur_mi\xf0vikudagur_fimmtudagur_f\xf6studagur_laugardagur".split("_"),weekdaysShort:"sun_m\xe1n_\xferi_mi\xf0_fim_f\xf6s_lau".split("_"),weekdaysMin:"Su_M\xe1_\xder_Mi_Fi_F\xf6_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[\xed dag kl.] LT",nextDay:"[\xe1 morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[\xed g\xe6r kl.] LT",lastWeek:"[s\xed\xf0asta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s s\xed\xf0an",s:n,ss:n,m:n,mm:n,h:"klukkustund",hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},Bs8V:function(e,t,n){var i=n("g6v/"),r=n("0eef"),s=n("XGwC"),o=n("/GqU"),a=n("wE6v"),c=n("UTVS"),l=n("DPsx"),u=Object.getOwnPropertyDescriptor;t.f=i?u:function(e,t){if(e=o(e),t=a(t,!0),l)try{return u(e,t)}catch(n){}if(c(e,t))return s(!r.f.call(e,t),e[t])}},ByF4:function(e,t,n){!function(e){"use strict";e.defineLocale("fo",{months:"januar_februar_mars_apr\xedl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_m\xe1nadagur_t\xfdsdagur_mikudagur_h\xf3sdagur_fr\xedggjadagur_leygardagur".split("_"),weekdaysShort:"sun_m\xe1n_t\xfds_mik_h\xf3s_fr\xed_ley".split("_"),weekdaysMin:"su_m\xe1_t\xfd_mi_h\xf3_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[\xcd dag kl.] LT",nextDay:"[\xcd morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[\xcd gj\xe1r kl.] LT",lastWeek:"[s\xed\xf0stu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s s\xed\xf0ani",s:"f\xe1 sekund",ss:"%d sekundir",m:"ein minuttur",mm:"%d minuttir",h:"ein t\xedmi",hh:"%d t\xedmar",d:"ein dagur",dd:"%d dagar",M:"ein m\xe1na\xf0ur",MM:"%d m\xe1na\xf0ir",y:"eitt \xe1r",yy:"%d \xe1r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},Ce4a:function(e,t,n){"use strict";var i=n("Ju5/");t.a=i.a.Uint8Array},CfRg:function(e,t,n){"use strict";var i=n("oSzE"),r=n("23KU"),s=n("+EKe"),o=n("mkut"),a=n("4/q3"),c=n("3/ER"),l=n("eAQQ"),u=n("jN84"),d=n("n561"),h=n("TFwu"),f=n("TnHx"),p=n("YM6B"),m=Object.prototype.hasOwnProperty,b=n("lkxz"),g=/\w*$/,_=n("ylTp"),y=_.a?_.a.prototype:void 0,v=y?y.valueOf:void 0,w=n("G4mU"),S=n("hYPf"),M=n("/1FC"),x=n("WOAq"),k=n("EUcb"),D=n("ovuK"),T=n("xutz"),C=T.a&&T.a.isMap,O=C?Object(D.a)(C):function(e){return Object(k.a)(e)&&"[object Map]"==Object(p.a)(e)},L=n("IzLi"),R=T.a&&T.a.isSet,E=R?Object(D.a)(R):function(e){return Object(k.a)(e)&&"[object Set]"==Object(p.a)(e)},A="[object Arguments]",I="[object Function]",P="[object Object]",j={};j[A]=j["[object Array]"]=j["[object ArrayBuffer]"]=j["[object DataView]"]=j["[object Boolean]"]=j["[object Date]"]=j["[object Float32Array]"]=j["[object Float64Array]"]=j["[object Int8Array]"]=j["[object Int16Array]"]=j["[object Int32Array]"]=j["[object Map]"]=j["[object Number]"]=j[P]=j["[object RegExp]"]=j["[object Set]"]=j["[object String]"]=j["[object Symbol]"]=j["[object Uint8Array]"]=j["[object Uint8ClampedArray]"]=j["[object Uint16Array]"]=j["[object Uint32Array]"]=!0,j["[object Error]"]=j[I]=j["[object WeakMap]"]=!1,t.a=function e(t,n,_,y,k,D){var T,C=1&n,R=2&n,N=4&n;if(_&&(T=k?_(t,y,k,D):_(t)),void 0!==T)return T;if(!Object(L.a)(t))return t;var F=Object(M.a)(t);if(F){if(T=function(e){var t=e.length,n=new e.constructor(t);return t&&"string"==typeof e[0]&&m.call(e,"index")&&(n.index=e.index,n.input=e.input),n}(t),!C)return Object(l.a)(t,T)}else{var Y=Object(p.a)(t),z=Y==I||"[object GeneratorFunction]"==Y;if(Object(x.a)(t))return Object(c.a)(t,C);if(Y==P||Y==A||z&&!k){if(T=R||z?{}:Object(S.a)(t),!C)return R?function(e,t){return Object(s.a)(e,Object(d.a)(e),t)}(t,function(e,t){return e&&Object(s.a)(t,Object(a.a)(t),e)}(T,t)):function(e,t){return Object(s.a)(e,Object(u.a)(e),t)}(t,function(e,t){return e&&Object(s.a)(t,Object(o.a)(t),e)}(T,t))}else{if(!j[Y])return k?t:{};T=function(e,t,n){var i,r,s=e.constructor;switch(t){case"[object ArrayBuffer]":return Object(b.a)(e);case"[object Boolean]":case"[object Date]":return new s(+e);case"[object DataView]":return function(e,t){var n=t?Object(b.a)(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}(e,n);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return Object(w.a)(e,n);case"[object Map]":return new s;case"[object Number]":case"[object String]":return new s(e);case"[object RegExp]":return(r=new(i=e).constructor(i.source,g.exec(i))).lastIndex=i.lastIndex,r;case"[object Set]":return new s;case"[object Symbol]":return v?Object(v.call(e)):{}}}(t,Y,C)}}D||(D=new i.a);var $=D.get(t);if($)return $;D.set(t,T),E(t)?t.forEach((function(i){T.add(e(i,n,_,i,t,D))})):O(t)&&t.forEach((function(i,r){T.set(r,e(i,n,_,r,t,D))}));var H=F?void 0:(N?R?f.a:h.a:R?a.a:o.a)(t);return function(e,t){for(var n=-1,i=null==e?0:e.length;++n{const i=new s.a;return i.add(t.schedule(()=>{const r=e[o.a]();i.add(r.subscribe({next(e){i.add(t.schedule(()=>n.next(e)))},error(e){i.add(t.schedule(()=>n.error(e)))},complete(){i.add(t.schedule(()=>n.complete()))}}))})),i})}(e,t);if(Object(l.a)(e))return function(e,t){return new i.a(n=>{const i=new s.a;return i.add(t.schedule(()=>e.then(e=>{i.add(t.schedule(()=>{n.next(e),i.add(t.schedule(()=>n.complete()))}))},e=>{i.add(t.schedule(()=>n.error(e)))}))),i})}(e,t);if(Object(u.a)(e))return Object(a.a)(e,t);if(function(e){return e&&"function"==typeof e[c.a]}(e)||"string"==typeof e)return function(e,t){if(!e)throw new Error("Iterable cannot be null");return new i.a(n=>{const i=new s.a;let r;return i.add(()=>{r&&"function"==typeof r.return&&r.return()}),i.add(t.schedule(()=>{r=e[c.a](),i.add(t.schedule((function(){if(n.closed)return;let e,t;try{const n=r.next();e=n.value,t=n.done}catch(i){return void n.error(i)}t?n.complete():(n.next(e),this.schedule())})))})),i})}(e,t)}throw new TypeError((null!==e&&typeof e||e)+" is not observable")}(e,t):e instanceof i.a?e:new i.a(Object(r.a)(e))}},ChqD:function(e,t,n){"use strict";n.d(t,"a",(function(){return h}));var i=n("SVse"),r=n("s7LF"),s=n("iInd"),o=n("G0yt"),a=n("w9WL"),c=n("zWsK"),l=n("V/fk"),u=n("9Xeq"),d=n("8Y7J");let h=(()=>{class e{}return e.\u0275mod=d.Kb({type:e}),e.\u0275inj=d.Jb({factory:function(t){return new(t||e)},imports:[[i.c,a.h,c.a,r.m,o.l,o.F,u.a,l.a,s.i],a.h]}),e})()},CjzT:function(e,t,n){!function(e){"use strict";var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),n="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),i=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],r=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,i){return e?/-MMM-/.test(i)?n[e.month()]:t[e.month()]:t},monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,weekdays:"domingo_lunes_martes_mi\xe9rcoles_jueves_viernes_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\xe9._jue._vie._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[ma\xf1ana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un a\xf1o",yy:"%d a\xf1os"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:1,doy:4}})}(n("wd/R"))},CoRJ:function(e,t,n){!function(e){"use strict";e.defineLocale("ar-ma",{months:"\u064a\u0646\u0627\u064a\u0631_\u0641\u0628\u0631\u0627\u064a\u0631_\u0645\u0627\u0631\u0633_\u0623\u0628\u0631\u064a\u0644_\u0645\u0627\u064a_\u064a\u0648\u0646\u064a\u0648_\u064a\u0648\u0644\u064a\u0648\u0632_\u063a\u0634\u062a_\u0634\u062a\u0646\u0628\u0631_\u0623\u0643\u062a\u0648\u0628\u0631_\u0646\u0648\u0646\u0628\u0631_\u062f\u062c\u0646\u0628\u0631".split("_"),monthsShort:"\u064a\u0646\u0627\u064a\u0631_\u0641\u0628\u0631\u0627\u064a\u0631_\u0645\u0627\u0631\u0633_\u0623\u0628\u0631\u064a\u0644_\u0645\u0627\u064a_\u064a\u0648\u0646\u064a\u0648_\u064a\u0648\u0644\u064a\u0648\u0632_\u063a\u0634\u062a_\u0634\u062a\u0646\u0628\u0631_\u0623\u0643\u062a\u0648\u0628\u0631_\u0646\u0648\u0646\u0628\u0631_\u062f\u062c\u0646\u0628\u0631".split("_"),weekdays:"\u0627\u0644\u0623\u062d\u062f_\u0627\u0644\u0625\u062b\u0646\u064a\u0646_\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621_\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621_\u0627\u0644\u062e\u0645\u064a\u0633_\u0627\u0644\u062c\u0645\u0639\u0629_\u0627\u0644\u0633\u0628\u062a".split("_"),weekdaysShort:"\u0627\u062d\u062f_\u0627\u062b\u0646\u064a\u0646_\u062b\u0644\u0627\u062b\u0627\u0621_\u0627\u0631\u0628\u0639\u0627\u0621_\u062e\u0645\u064a\u0633_\u062c\u0645\u0639\u0629_\u0633\u0628\u062a".split("_"),weekdaysMin:"\u062d_\u0646_\u062b_\u0631_\u062e_\u062c_\u0633".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[\u0627\u0644\u064a\u0648\u0645 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextDay:"[\u063a\u062f\u0627 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextWeek:"dddd [\u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastDay:"[\u0623\u0645\u0633 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastWeek:"dddd [\u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",sameElse:"L"},relativeTime:{future:"\u0641\u064a %s",past:"\u0645\u0646\u0630 %s",s:"\u062b\u0648\u0627\u0646",ss:"%d \u062b\u0627\u0646\u064a\u0629",m:"\u062f\u0642\u064a\u0642\u0629",mm:"%d \u062f\u0642\u0627\u0626\u0642",h:"\u0633\u0627\u0639\u0629",hh:"%d \u0633\u0627\u0639\u0627\u062a",d:"\u064a\u0648\u0645",dd:"%d \u0623\u064a\u0627\u0645",M:"\u0634\u0647\u0631",MM:"%d \u0623\u0634\u0647\u0631",y:"\u0633\u0646\u0629",yy:"%d \u0633\u0646\u0648\u0627\u062a"},week:{dow:1,doy:4}})}(n("wd/R"))},CqXF:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("7o/Q");function r(e){return t=>t.lift(new s(e))}class s{constructor(e){this.value=e}call(e,t){return t.subscribe(new o(e,this.value))}}class o extends i.a{constructor(e,t){super(e),this.value=t}_next(e){this.destination.next(this.value)}}},"D/JM":function(e,t,n){!function(e){"use strict";e.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",ss:"%d segundo",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(n("wd/R"))},D0XW:function(e,t,n){"use strict";n.d(t,"b",(function(){return r})),n.d(t,"a",(function(){return s}));var i=n("3N8a");const r=new(n("IjjT").a)(i.a),s=r},D4zM:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{constructor(e,t){this.elementRef=e,this.renderer=t}ngOnInit(){this.renderer.setAttribute(this.elementRef.nativeElement,"tabindex","-1"),this.iElement=this.renderer.createElement("i"),this.renderer.addClass(this.iElement,"fa"),this.renderer.appendChild(this.elementRef.nativeElement,this.iElement),this.update()}getInputElement(){return document.getElementById(this.cdPasswordButton)}update(){const e=this.getInputElement();e&&"text"===e.type?(this.renderer.removeClass(this.iElement,"fa-eye"),this.renderer.addClass(this.iElement,"fa-eye-slash")):(this.renderer.removeClass(this.iElement,"fa-eye-slash"),this.renderer.addClass(this.iElement,"fa-eye"))}onClick(){const e=this.getInputElement();e.type="password"===e.type?"text":"password",this.update()}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m),i.Mb(i.E))},e.\u0275dir=i.Hb({type:e,selectors:[["","cdPasswordButton",""]],hostBindings:function(e,t){1&e&&i.gc("click",(function(){return t.onClick()}))},inputs:{cdPasswordButton:"cdPasswordButton"}}),e})()},DH7j:function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));const i=(()=>Array.isArray||(e=>e&&"number"==typeof e.length))()},"DKr+":function(e,t,n){!function(e){"use strict";function t(e,t,n,i){var r={s:["thoddea sekondamni","thodde sekond"],ss:[e+" sekondamni",e+" sekond"],m:["eka mintan","ek minut"],mm:[e+" mintamni",e+" mintam"],h:["eka voran","ek vor"],hh:[e+" voramni",e+" voram"],d:["eka disan","ek dis"],dd:[e+" disamni",e+" dis"],M:["eka mhoinean","ek mhoino"],MM:[e+" mhoineamni",e+" mhoine"],y:["eka vorsan","ek voros"],yy:[e+" vorsamni",e+" vorsam"]};return i?r[n][0]:r[n][1]}e.defineLocale("gom-latn",{months:{standalone:"Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr".split("_"),format:"Janerachea_Febrerachea_Marsachea_Abrilachea_Maiachea_Junachea_Julaiachea_Agostachea_Setembrachea_Otubrachea_Novembrachea_Dezembrachea".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Aitar_Somar_Mongllar_Budhvar_Birestar_Sukrar_Son'var".split("_"),weekdaysShort:"Ait._Som._Mon._Bud._Bre._Suk._Son.".split("_"),weekdaysMin:"Ai_Sm_Mo_Bu_Br_Su_Sn".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [vazta]",LTS:"A h:mm:ss [vazta]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [vazta]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [vazta]",llll:"ddd, D MMM YYYY, A h:mm [vazta]"},calendar:{sameDay:"[Aiz] LT",nextDay:"[Faleam] LT",nextWeek:"[Fuddlo] dddd[,] LT",lastDay:"[Kal] LT",lastWeek:"[Fattlo] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s adim",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}(er)/,ordinal:function(e,t){switch(t){case"D":return e+"er";default:case"M":case"Q":case"DDD":case"d":case"w":case"W":return e}},week:{dow:0,doy:3},meridiemParse:/rati|sokallim|donparam|sanje/,meridiemHour:function(e,t){return 12===e&&(e=0),"rati"===t?e<4?e:e+12:"sokallim"===t?e:"donparam"===t?e>12?e:e+12:"sanje"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"rati":e<12?"sokallim":e<16?"donparam":e<20?"sanje":"rati"}})}(n("wd/R"))},DLK6:function(e,t,n){var i=n("ewvW"),r=Math.floor,s="".replace,o=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,a=/\$([$&'`]|\d{1,2})/g;e.exports=function(e,t,n,c,l,u){var d=n+e.length,h=c.length,f=a;return void 0!==l&&(l=i(l),f=o),s.call(u,f,(function(i,s){var o;switch(s.charAt(0)){case"$":return"$";case"&":return e;case"`":return t.slice(0,n);case"'":return t.slice(d);case"<":o=l[s.slice(1,-1)];break;default:var a=+s;if(0===a)return i;if(a>h){var u=r(a/10);return 0===u?i:u<=h?void 0===c[u-1]?s.charAt(1):c[u-1]+s.charAt(1):i}o=c[a-1]}return void 0===o?"":o}))}},DNAf:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("LvDl"),r=n.n(i);class s{constructor(e){this.customValidations={},this.empty="No items selected.",this.selectionLimit={tooltip:"Deselect item to select again",text:"Selection limit reached"},this.filter="Filter tags",this.add="Add badge",this.noOptions="There are no items available.",r.a.merge(this,e)}}},DPsx:function(e,t,n){var i=n("g6v/"),r=n("0Dky"),s=n("zBJ4");e.exports=!i&&!r((function(){return 7!=Object.defineProperty(s("div"),"a",{get:function(){return 7}}).a}))},DSvg:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("LvDl"),r=n("vkgz"),s=n("aexS"),o=n("8Y7J"),a=n("IheW"),c=n("iInd");let l=(()=>{class e{constructor(e,t,n,i){this.authStorageService=e,this.http=t,this.router=n,this.route=i}check(e){return this.http.post("api/auth/check",{token:e})}login(e){return this.http.post("api/auth",e).pipe(Object(r.a)(e=>{this.authStorageService.set(e.username,e.permissions,e.sso,e.pwdExpirationDate,e.pwdUpdateRequired)}))}logout(e=null){return this.http.post("api/auth/logout",null).subscribe(t=>{this.authStorageService.remove();const n=i.get(this.route.snapshot.queryParams,"returnUrl","/login");this.router.navigate([n],{skipLocationChange:!0}),e&&e(),window.location.replace(t.redirect_url)})}}return e.\u0275fac=function(t){return new(t||e)(o.dc(s.a),o.dc(a.b),o.dc(c.e),o.dc(c.a))},e.\u0275prov=o.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},Dkky:function(e,t,n){!function(e){"use strict";e.defineLocale("fr-ch",{months:"janvier_f\xe9vrier_mars_avril_mai_juin_juillet_ao\xfbt_septembre_octobre_novembre_d\xe9cembre".split("_"),monthsShort:"janv._f\xe9vr._mars_avr._mai_juin_juil._ao\xfbt_sept._oct._nov._d\xe9c.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd\u2019hui \xe0] LT",nextDay:"[Demain \xe0] LT",nextWeek:"dddd [\xe0] LT",lastDay:"[Hier \xe0] LT",lastWeek:"dddd [dernier \xe0] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,t){switch(t){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(n("wd/R"))},DlmY:function(e,t,n){"use strict";var i=n("Y7yP"),r=Object(i.a)(Object,"create"),s=Object.prototype.hasOwnProperty,o=Object.prototype.hasOwnProperty;function a(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t=100?100:null])}},week:{dow:1,doy:7}})}(n("wd/R"))},Dwqy:function(e,t,n){"use strict";n.d(t,"a",(function(){return c}));var i=n("LvDl"),r=n.n(i),s=n("wd/R"),o=n.n(s),a=n("8Y7J");o.a.updateLocale("en",{relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"}});let c=(()=>{class e{transform(e,t=!0){let n;if(n=r.a.isNumber(e)?o.a.unix(e):o()(e),!n.isValid())return"";let i=n.fromNow();return t&&(i=r.a.upperFirst(i)),i}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=a.Lb({name:"relativeDate",type:e,pure:!1}),e})()},DxQv:function(e,t,n){!function(e){"use strict";e.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"s\xf8ndag_mandag_tirsdag_onsdag_torsdag_fredag_l\xf8rdag".split("_"),weekdaysShort:"s\xf8n_man_tir_ons_tor_fre_l\xf8r".split("_"),weekdaysMin:"s\xf8_ma_ti_on_to_fr_l\xf8".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"p\xe5 dddd [kl.] LT",lastDay:"[i g\xe5r kl.] LT",lastWeek:"[i] dddd[s kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"f\xe5 sekunder",ss:"%d sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en m\xe5ned",MM:"%d m\xe5neder",y:"et \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},Dzi0:function(e,t,n){!function(e){"use strict";e.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(n("wd/R"))},"E+lV":function(e,t,n){!function(e){"use strict";var t={words:{ss:["\u0441\u0435\u043a\u0443\u043d\u0434\u0430","\u0441\u0435\u043a\u0443\u043d\u0434\u0435","\u0441\u0435\u043a\u0443\u043d\u0434\u0438"],m:["\u0458\u0435\u0434\u0430\u043d \u043c\u0438\u043d\u0443\u0442","\u0458\u0435\u0434\u043d\u0435 \u043c\u0438\u043d\u0443\u0442\u0435"],mm:["\u043c\u0438\u043d\u0443\u0442","\u043c\u0438\u043d\u0443\u0442\u0435","\u043c\u0438\u043d\u0443\u0442\u0430"],h:["\u0458\u0435\u0434\u0430\u043d \u0441\u0430\u0442","\u0458\u0435\u0434\u043d\u043e\u0433 \u0441\u0430\u0442\u0430"],hh:["\u0441\u0430\u0442","\u0441\u0430\u0442\u0430","\u0441\u0430\u0442\u0438"],dd:["\u0434\u0430\u043d","\u0434\u0430\u043d\u0430","\u0434\u0430\u043d\u0430"],MM:["\u043c\u0435\u0441\u0435\u0446","\u043c\u0435\u0441\u0435\u0446\u0430","\u043c\u0435\u0441\u0435\u0446\u0438"],yy:["\u0433\u043e\u0434\u0438\u043d\u0430","\u0433\u043e\u0434\u0438\u043d\u0435","\u0433\u043e\u0434\u0438\u043d\u0430"]},correctGrammaticalCase:function(e,t){return 1===e?t[0]:e>=2&&e<=4?t[1]:t[2]},translate:function(e,n,i){var r=t.words[i];return 1===i.length?n?r[0]:r[1]:e+" "+t.correctGrammaticalCase(e,r)}};e.defineLocale("sr-cyrl",{months:"\u0458\u0430\u043d\u0443\u0430\u0440_\u0444\u0435\u0431\u0440\u0443\u0430\u0440_\u043c\u0430\u0440\u0442_\u0430\u043f\u0440\u0438\u043b_\u043c\u0430\u0458_\u0458\u0443\u043d_\u0458\u0443\u043b_\u0430\u0432\u0433\u0443\u0441\u0442_\u0441\u0435\u043f\u0442\u0435\u043c\u0431\u0430\u0440_\u043e\u043a\u0442\u043e\u0431\u0430\u0440_\u043d\u043e\u0432\u0435\u043c\u0431\u0430\u0440_\u0434\u0435\u0446\u0435\u043c\u0431\u0430\u0440".split("_"),monthsShort:"\u0458\u0430\u043d._\u0444\u0435\u0431._\u043c\u0430\u0440._\u0430\u043f\u0440._\u043c\u0430\u0458_\u0458\u0443\u043d_\u0458\u0443\u043b_\u0430\u0432\u0433._\u0441\u0435\u043f._\u043e\u043a\u0442._\u043d\u043e\u0432._\u0434\u0435\u0446.".split("_"),monthsParseExact:!0,weekdays:"\u043d\u0435\u0434\u0435\u0459\u0430_\u043f\u043e\u043d\u0435\u0434\u0435\u0459\u0430\u043a_\u0443\u0442\u043e\u0440\u0430\u043a_\u0441\u0440\u0435\u0434\u0430_\u0447\u0435\u0442\u0432\u0440\u0442\u0430\u043a_\u043f\u0435\u0442\u0430\u043a_\u0441\u0443\u0431\u043e\u0442\u0430".split("_"),weekdaysShort:"\u043d\u0435\u0434._\u043f\u043e\u043d._\u0443\u0442\u043e._\u0441\u0440\u0435._\u0447\u0435\u0442._\u043f\u0435\u0442._\u0441\u0443\u0431.".split("_"),weekdaysMin:"\u043d\u0435_\u043f\u043e_\u0443\u0442_\u0441\u0440_\u0447\u0435_\u043f\u0435_\u0441\u0443".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[\u0434\u0430\u043d\u0430\u0441 \u0443] LT",nextDay:"[\u0441\u0443\u0442\u0440\u0430 \u0443] LT",nextWeek:function(){switch(this.day()){case 0:return"[\u0443] [\u043d\u0435\u0434\u0435\u0459\u0443] [\u0443] LT";case 3:return"[\u0443] [\u0441\u0440\u0435\u0434\u0443] [\u0443] LT";case 6:return"[\u0443] [\u0441\u0443\u0431\u043e\u0442\u0443] [\u0443] LT";case 1:case 2:case 4:case 5:return"[\u0443] dddd [\u0443] LT"}},lastDay:"[\u0458\u0443\u0447\u0435 \u0443] LT",lastWeek:function(){return["[\u043f\u0440\u043e\u0448\u043b\u0435] [\u043d\u0435\u0434\u0435\u0459\u0435] [\u0443] LT","[\u043f\u0440\u043e\u0448\u043b\u043e\u0433] [\u043f\u043e\u043d\u0435\u0434\u0435\u0459\u043a\u0430] [\u0443] LT","[\u043f\u0440\u043e\u0448\u043b\u043e\u0433] [\u0443\u0442\u043e\u0440\u043a\u0430] [\u0443] LT","[\u043f\u0440\u043e\u0448\u043b\u0435] [\u0441\u0440\u0435\u0434\u0435] [\u0443] LT","[\u043f\u0440\u043e\u0448\u043b\u043e\u0433] [\u0447\u0435\u0442\u0432\u0440\u0442\u043a\u0430] [\u0443] LT","[\u043f\u0440\u043e\u0448\u043b\u043e\u0433] [\u043f\u0435\u0442\u043a\u0430] [\u0443] LT","[\u043f\u0440\u043e\u0448\u043b\u0435] [\u0441\u0443\u0431\u043e\u0442\u0435] [\u0443] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"\u0437\u0430 %s",past:"\u043f\u0440\u0435 %s",s:"\u043d\u0435\u043a\u043e\u043b\u0438\u043a\u043e \u0441\u0435\u043a\u0443\u043d\u0434\u0438",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:"\u0434\u0430\u043d",dd:t.translate,M:"\u043c\u0435\u0441\u0435\u0446",MM:t.translate,y:"\u0433\u043e\u0434\u0438\u043d\u0443",yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(n("wd/R"))},E2fk:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){return"[DBG]"===e?"debug":"[INF]"===e?"info":"[WRN]"===e?"warn":"[ERR]"===e?"err":""}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"logPriority",type:e,pure:!0}),e})()},E9XD:function(e,t,n){"use strict";var i=n("I+eb"),r=n("1Y/n").left,s=n("pkCn"),o=n("LQDL"),a=n("YF1G");i({target:"Array",proto:!0,forced:!s("reduce")||!a&&o>79&&o<83},{reduce:function(e){return r(this,e,arguments.length,arguments.length>1?arguments[1]:void 0)}})},EApP:function(e,t,n){"use strict";n.d(t,"a",(function(){return C})),n.d(t,"b",(function(){return k}));var i=n("8Y7J"),r=n("GS7A"),s=n("XNiG"),o=n("cUpR"),a=n("SVse");const c=["toast-component",""];function l(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",5),i.gc("click",(function(){return i.Dc(e),i.ic().remove()})),i.Sb(1,"span",6),i.Oc(2,"\xd7"),i.Rb(),i.Rb()}}function u(e,t){if(1&e&&(i.Qb(0),i.Oc(1),i.Pb()),2&e){const e=i.ic(2);i.yb(1),i.Qc("[",e.duplicatesCount+1,"]")}}function d(e,t){if(1&e&&(i.Sb(0,"div"),i.Oc(1),i.Mc(2,u,2,1,"ng-container",4),i.Rb()),2&e){const e=i.ic();i.Ab(e.options.titleClass),i.zb("aria-label",e.title),i.yb(1),i.Qc(" ",e.title," "),i.yb(1),i.pc("ngIf",e.duplicatesCount)}}function h(e,t){if(1&e&&i.Nb(0,"div",7),2&e){const e=i.ic();i.Ab(e.options.messageClass),i.pc("innerHTML",e.message,i.Ec)}}function f(e,t){if(1&e&&(i.Sb(0,"div",8),i.Oc(1),i.Rb()),2&e){const e=i.ic();i.Ab(e.options.messageClass),i.zb("aria-label",e.message),i.yb(1),i.Qc(" ",e.message," ")}}function p(e,t){if(1&e&&(i.Sb(0,"div"),i.Nb(1,"div",9),i.Rb()),2&e){const e=i.ic();i.yb(1),i.Kc("width",e.width+"%")}}class m{constructor(e,t,n,i,r,o){this.toastId=e,this.config=t,this.message=n,this.title=i,this.toastType=r,this.toastRef=o,this._onTap=new s.a,this._onAction=new s.a,this.toastRef.afterClosed().subscribe(()=>{this._onAction.complete(),this._onTap.complete()})}triggerTap(){this._onTap.next(),this.config.tapToDismiss&&this._onTap.complete()}onTap(){return this._onTap.asObservable()}triggerAction(e){this._onAction.next(e)}onAction(){return this._onAction.asObservable()}}const b={maxOpened:0,autoDismiss:!1,newestOnTop:!0,preventDuplicates:!1,countDuplicates:!1,resetTimeoutOnDuplicate:!1,includeTitleDuplicates:!1,iconClasses:{error:"toast-error",info:"toast-info",success:"toast-success",warning:"toast-warning"},closeButton:!1,disableTimeOut:!1,timeOut:5e3,extendedTimeOut:1e3,enableHtml:!1,progressBar:!1,toastClass:"ngx-toastr",positionClass:"toast-top-right",titleClass:"toast-title",messageClass:"toast-message",easing:"ease-in",easeTime:300,tapToDismiss:!0,onActivateTick:!1,progressAnimation:"decreasing"},g=new i.r("ToastConfig");class _{constructor(e,t){this.component=e,this.injector=t}attach(e,t){return this._attachedHost=e,e.attach(this,t)}detach(){const e=this._attachedHost;if(e)return this._attachedHost=void 0,e.detach()}get isAttached(){return null!=this._attachedHost}setAttachedHost(e){this._attachedHost=e}}class y extends class{attach(e,t){return this._attachedPortal=e,this.attachComponentPortal(e,t)}detach(){this._attachedPortal&&this._attachedPortal.setAttachedHost(),this._attachedPortal=void 0,this._disposeFn&&(this._disposeFn(),this._disposeFn=void 0)}setDisposeFn(e){this._disposeFn=e}}{constructor(e,t,n){super(),this._hostDomElement=e,this._componentFactoryResolver=t,this._appRef=n}attachComponentPortal(e,t){const n=this._componentFactoryResolver.resolveComponentFactory(e.component);let i;return i=n.create(e.injector),this._appRef.attachView(i.hostView),this.setDisposeFn(()=>{this._appRef.detachView(i.hostView),i.destroy()}),t?this._hostDomElement.insertBefore(this._getComponentRootNode(i),this._hostDomElement.firstChild):this._hostDomElement.appendChild(this._getComponentRootNode(i)),i}_getComponentRootNode(e){return e.hostView.rootNodes[0]}}let v=(()=>{class e{constructor(e){this._document=e}ngOnDestroy(){this._containerElement&&this._containerElement.parentNode&&this._containerElement.parentNode.removeChild(this._containerElement)}getContainerElement(){return this._containerElement||this._createContainer(),this._containerElement}_createContainer(){const e=this._document.createElement("div");e.classList.add("overlay-container"),this._document.body.appendChild(e),this._containerElement=e}}return e.\u0275fac=function(t){return new(t||e)(i.dc(a.d))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(a.d))},token:e,providedIn:"root"}),e})();class w{constructor(e){this._portalHost=e}attach(e,t=!0){return this._portalHost.attach(e,t)}detach(){return this._portalHost.detach()}}let S=(()=>{class e{constructor(e,t,n,i){this._overlayContainer=e,this._componentFactoryResolver=t,this._appRef=n,this._document=i,this._paneElements=new Map}create(e,t){return this._createOverlayRef(this.getPaneElement(e,t))}getPaneElement(e="",t){return this._paneElements.get(t)||this._paneElements.set(t,{}),this._paneElements.get(t)[e]||(this._paneElements.get(t)[e]=this._createPaneElement(e,t)),this._paneElements.get(t)[e]}_createPaneElement(e,t){const n=this._document.createElement("div");return n.id="toast-container",n.classList.add(e),n.classList.add("toast-container"),t?t.getContainerElement().appendChild(n):this._overlayContainer.getContainerElement().appendChild(n),n}_createPortalHost(e){return new y(e,this._componentFactoryResolver,this._appRef)}_createOverlayRef(e){return new w(this._createPortalHost(e))}}return e.\u0275fac=function(t){return new(t||e)(i.dc(v),i.dc(i.j),i.dc(i.g),i.dc(a.d))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(v),Object(i.dc)(i.j),Object(i.dc)(i.g),Object(i.dc)(a.d))},token:e,providedIn:"root"}),e})();class M{constructor(e){this._overlayRef=e,this.duplicatesCount=0,this._afterClosed=new s.a,this._activate=new s.a,this._manualClose=new s.a,this._resetTimeout=new s.a,this._countDuplicate=new s.a}manualClose(){this._manualClose.next(),this._manualClose.complete()}manualClosed(){return this._manualClose.asObservable()}timeoutReset(){return this._resetTimeout.asObservable()}countDuplicate(){return this._countDuplicate.asObservable()}close(){this._overlayRef.detach(),this._afterClosed.next(),this._manualClose.next(),this._afterClosed.complete(),this._manualClose.complete(),this._activate.complete(),this._resetTimeout.complete(),this._countDuplicate.complete()}afterClosed(){return this._afterClosed.asObservable()}isInactive(){return this._activate.isStopped}activate(){this._activate.next(),this._activate.complete()}afterActivate(){return this._activate.asObservable()}onDuplicate(e,t){e&&this._resetTimeout.next(),t&&this._countDuplicate.next(++this.duplicatesCount)}}class x{constructor(e,t){this._toastPackage=e,this._parentInjector=t}get(e,t,n){return e===m?this._toastPackage:this._parentInjector.get(e,t,n)}}let k=(()=>{class e{constructor(e,t,n,i,r){this.overlay=t,this._injector=n,this.sanitizer=i,this.ngZone=r,this.currentlyActive=0,this.toasts=[],this.index=0,this.toastrConfig=Object.assign(Object.assign({},e.default),e.config),e.config.iconClasses&&(this.toastrConfig.iconClasses=Object.assign(Object.assign({},e.default.iconClasses),e.config.iconClasses))}show(e,t,n={},i=""){return this._preBuildNotification(i,e,t,this.applyConfig(n))}success(e,t,n={}){return this._preBuildNotification(this.toastrConfig.iconClasses.success||"",e,t,this.applyConfig(n))}error(e,t,n={}){return this._preBuildNotification(this.toastrConfig.iconClasses.error||"",e,t,this.applyConfig(n))}info(e,t,n={}){return this._preBuildNotification(this.toastrConfig.iconClasses.info||"",e,t,this.applyConfig(n))}warning(e,t,n={}){return this._preBuildNotification(this.toastrConfig.iconClasses.warning||"",e,t,this.applyConfig(n))}clear(e){for(const t of this.toasts)if(void 0!==e){if(t.toastId===e)return void t.toastRef.manualClose()}else t.toastRef.manualClose()}remove(e){const t=this._findToast(e);if(!t)return!1;if(t.activeToast.toastRef.close(),this.toasts.splice(t.index,1),this.currentlyActive=this.currentlyActive-1,!this.toastrConfig.maxOpened||!this.toasts.length)return!1;if(this.currentlyActivethis._buildNotification(e,t,n,i)):this._buildNotification(e,t,n,i)}_buildNotification(e,t,n,r){if(!r.toastComponent)throw new Error("toastComponent required");const s=this.findDuplicate(n,t,this.toastrConfig.resetTimeoutOnDuplicate&&r.timeOut>0,this.toastrConfig.countDuplicates);if((this.toastrConfig.includeTitleDuplicates&&n||t)&&this.toastrConfig.preventDuplicates&&null!==s)return s;this.previousToastMessage=t;let o=!1;this.toastrConfig.maxOpened&&this.currentlyActive>=this.toastrConfig.maxOpened&&(o=!0,this.toastrConfig.autoDismiss&&this.clear(this.toasts[0].toastId));const a=this.overlay.create(r.positionClass,this.overlayContainer);this.index=this.index+1;let c=t;t&&r.enableHtml&&(c=this.sanitizer.sanitize(i.I.HTML,t));const l=new M(a),u=new m(this.index,r,c,n,e,l),d=new x(u,this._injector),h=new _(r.toastComponent,d),f=a.attach(h,this.toastrConfig.newestOnTop);l.componentInstance=f.instance;const p={toastId:this.index,title:n||"",message:t||"",toastRef:l,onShown:l.afterActivate(),onHidden:l.afterClosed(),onTap:u.onTap(),onAction:u.onAction(),portal:f};return o||(this.currentlyActive=this.currentlyActive+1,setTimeout(()=>{p.toastRef.activate()})),this.toasts.push(p),p}}return e.\u0275fac=function(t){return new(t||e)(i.dc(g),i.dc(S),i.dc(i.s),i.dc(o.b),i.dc(i.A))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(g),Object(i.dc)(S),Object(i.dc)(i.p),Object(i.dc)(o.b),Object(i.dc)(i.A))},token:e,providedIn:"root"}),e})(),D=(()=>{class e{constructor(e,t,n){this.toastrService=e,this.toastPackage=t,this.ngZone=n,this.width=-1,this.toastClasses="",this.state={value:"inactive",params:{easeTime:this.toastPackage.config.easeTime,easing:"ease-in"}},this.message=t.message,this.title=t.title,this.options=t.config,this.originalTimeout=t.config.timeOut,this.toastClasses=`${t.toastType} ${t.config.toastClass}`,this.sub=t.toastRef.afterActivate().subscribe(()=>{this.activateToast()}),this.sub1=t.toastRef.manualClosed().subscribe(()=>{this.remove()}),this.sub2=t.toastRef.timeoutReset().subscribe(()=>{this.resetTimeout()}),this.sub3=t.toastRef.countDuplicate().subscribe(e=>{this.duplicatesCount=e})}get displayStyle(){if("inactive"===this.state.value)return"none"}ngOnDestroy(){this.sub.unsubscribe(),this.sub1.unsubscribe(),this.sub2.unsubscribe(),this.sub3.unsubscribe(),clearInterval(this.intervalId),clearTimeout(this.timeout)}activateToast(){this.state=Object.assign(Object.assign({},this.state),{value:"active"}),!0!==this.options.disableTimeOut&&"timeOut"!==this.options.disableTimeOut&&this.options.timeOut&&(this.outsideTimeout(()=>this.remove(),this.options.timeOut),this.hideTime=(new Date).getTime()+this.options.timeOut,this.options.progressBar&&this.outsideInterval(()=>this.updateProgress(),10))}updateProgress(){if(0===this.width||100===this.width||!this.options.timeOut)return;const e=(new Date).getTime();this.width=(this.hideTime-e)/this.options.timeOut*100,"increasing"===this.options.progressAnimation&&(this.width=100-this.width),this.width<=0&&(this.width=0),this.width>=100&&(this.width=100)}resetTimeout(){clearTimeout(this.timeout),clearInterval(this.intervalId),this.state=Object.assign(Object.assign({},this.state),{value:"active"}),this.outsideTimeout(()=>this.remove(),this.originalTimeout),this.options.timeOut=this.originalTimeout,this.hideTime=(new Date).getTime()+(this.options.timeOut||0),this.width=-1,this.options.progressBar&&this.outsideInterval(()=>this.updateProgress(),10)}remove(){"removed"!==this.state.value&&(clearTimeout(this.timeout),this.state=Object.assign(Object.assign({},this.state),{value:"removed"}),this.outsideTimeout(()=>this.toastrService.remove(this.toastPackage.toastId),+this.toastPackage.config.easeTime))}tapToast(){"removed"!==this.state.value&&(this.toastPackage.triggerTap(),this.options.tapToDismiss&&this.remove())}stickAround(){"removed"!==this.state.value&&(clearTimeout(this.timeout),this.options.timeOut=0,this.hideTime=0,clearInterval(this.intervalId),this.width=0)}delayedHideToast(){!0!==this.options.disableTimeOut&&"extendedTimeOut"!==this.options.disableTimeOut&&0!==this.options.extendedTimeOut&&"removed"!==this.state.value&&(this.outsideTimeout(()=>this.remove(),this.options.extendedTimeOut),this.options.timeOut=this.options.extendedTimeOut,this.hideTime=(new Date).getTime()+(this.options.timeOut||0),this.width=-1,this.options.progressBar&&this.outsideInterval(()=>this.updateProgress(),10))}outsideTimeout(e,t){this.ngZone?this.ngZone.runOutsideAngular(()=>this.timeout=setTimeout(()=>this.runInsideAngular(e),t)):this.timeout=setTimeout(()=>e(),t)}outsideInterval(e,t){this.ngZone?this.ngZone.runOutsideAngular(()=>this.intervalId=setInterval(()=>this.runInsideAngular(e),t)):this.intervalId=setInterval(()=>e(),t)}runInsideAngular(e){this.ngZone?this.ngZone.run(()=>e()):e()}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(k),i.Mb(m),i.Mb(i.A))},e.\u0275cmp=i.Gb({type:e,selectors:[["","toast-component",""]],hostVars:5,hostBindings:function(e,t){1&e&&i.gc("click",(function(){return t.tapToast()}))("mouseenter",(function(){return t.stickAround()}))("mouseleave",(function(){return t.delayedHideToast()})),2&e&&(i.Lc("@flyInOut",t.state),i.Ab(t.toastClasses),i.Kc("display",t.displayStyle))},attrs:c,decls:5,vars:5,consts:[["class","toast-close-button","aria-label","Close",3,"click",4,"ngIf"],[3,"class",4,"ngIf"],["role","alertdialog","aria-live","polite",3,"class","innerHTML",4,"ngIf"],["role","alertdialog","aria-live","polite",3,"class",4,"ngIf"],[4,"ngIf"],["aria-label","Close",1,"toast-close-button",3,"click"],["aria-hidden","true"],["role","alertdialog","aria-live","polite",3,"innerHTML"],["role","alertdialog","aria-live","polite"],[1,"toast-progress"]],template:function(e,t){1&e&&(i.Mc(0,l,3,0,"button",0),i.Mc(1,d,3,5,"div",1),i.Mc(2,h,1,3,"div",2),i.Mc(3,f,2,4,"div",3),i.Mc(4,p,2,2,"div",4)),2&e&&(i.pc("ngIf",t.options.closeButton),i.yb(1),i.pc("ngIf",t.title),i.yb(1),i.pc("ngIf",t.message&&t.options.enableHtml),i.yb(1),i.pc("ngIf",t.message&&!t.options.enableHtml),i.yb(1),i.pc("ngIf",t.options.progressBar))},directives:[a.r],encapsulation:2,data:{animation:[Object(r.j)("flyInOut",[Object(r.g)("inactive",Object(r.h)({opacity:0})),Object(r.g)("active",Object(r.h)({opacity:1})),Object(r.g)("removed",Object(r.h)({opacity:0})),Object(r.i)("inactive => active",Object(r.e)("{{ easeTime }}ms {{ easing }}")),Object(r.i)("active => removed",Object(r.e)("{{ easeTime }}ms {{ easing }}"))])]}}),e})();const T=Object.assign(Object.assign({},b),{toastComponent:D});let C=(()=>{class e{static forRoot(t={}){return{ngModule:e,providers:[{provide:g,useValue:{default:T,config:t}}]}}}return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[a.c]]}),e})()},ENF9:function(e,t,n){"use strict";var i,r=n("2oRo"),s=n("4syw"),o=n("8YOa"),a=n("bWFh"),c=n("rKzb"),l=n("hh1v"),u=n("afO8").enforce,d=n("f5p1"),h=!r.ActiveXObject&&"ActiveXObject"in r,f=Object.isExtensible,p=function(e){return function(){return e(this,arguments.length?arguments[0]:void 0)}},m=e.exports=a("WeakMap",p,c);if(d&&h){i=c.getConstructor(p,"WeakMap",!0),o.REQUIRED=!0;var b=m.prototype,g=b.delete,_=b.has,y=b.get,v=b.set;s(b,{delete:function(e){if(l(e)&&!f(e)){var t=u(this);return t.frozen||(t.frozen=new i),g.call(this,e)||t.frozen.delete(e)}return g.call(this,e)},has:function(e){if(l(e)&&!f(e)){var t=u(this);return t.frozen||(t.frozen=new i),_.call(this,e)||t.frozen.has(e)}return _.call(this,e)},get:function(e){if(l(e)&&!f(e)){var t=u(this);return t.frozen||(t.frozen=new i),_.call(this,e)?y.call(this,e):t.frozen.get(e)}return y.call(this,e)},set:function(e,t){if(l(e)&&!f(e)){var n=u(this);n.frozen||(n.frozen=new i),_.call(this,e)?v.call(this,e,t):n.frozen.set(e,t)}else v.call(this,e,t);return this}})}},EOgW:function(e,t,n){!function(e){"use strict";e.defineLocale("th",{months:"\u0e21\u0e01\u0e23\u0e32\u0e04\u0e21_\u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c_\u0e21\u0e35\u0e19\u0e32\u0e04\u0e21_\u0e40\u0e21\u0e29\u0e32\u0e22\u0e19_\u0e1e\u0e24\u0e29\u0e20\u0e32\u0e04\u0e21_\u0e21\u0e34\u0e16\u0e38\u0e19\u0e32\u0e22\u0e19_\u0e01\u0e23\u0e01\u0e0e\u0e32\u0e04\u0e21_\u0e2a\u0e34\u0e07\u0e2b\u0e32\u0e04\u0e21_\u0e01\u0e31\u0e19\u0e22\u0e32\u0e22\u0e19_\u0e15\u0e38\u0e25\u0e32\u0e04\u0e21_\u0e1e\u0e24\u0e28\u0e08\u0e34\u0e01\u0e32\u0e22\u0e19_\u0e18\u0e31\u0e19\u0e27\u0e32\u0e04\u0e21".split("_"),monthsShort:"\u0e21.\u0e04._\u0e01.\u0e1e._\u0e21\u0e35.\u0e04._\u0e40\u0e21.\u0e22._\u0e1e.\u0e04._\u0e21\u0e34.\u0e22._\u0e01.\u0e04._\u0e2a.\u0e04._\u0e01.\u0e22._\u0e15.\u0e04._\u0e1e.\u0e22._\u0e18.\u0e04.".split("_"),monthsParseExact:!0,weekdays:"\u0e2d\u0e32\u0e17\u0e34\u0e15\u0e22\u0e4c_\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c_\u0e2d\u0e31\u0e07\u0e04\u0e32\u0e23_\u0e1e\u0e38\u0e18_\u0e1e\u0e24\u0e2b\u0e31\u0e2a\u0e1a\u0e14\u0e35_\u0e28\u0e38\u0e01\u0e23\u0e4c_\u0e40\u0e2a\u0e32\u0e23\u0e4c".split("_"),weekdaysShort:"\u0e2d\u0e32\u0e17\u0e34\u0e15\u0e22\u0e4c_\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c_\u0e2d\u0e31\u0e07\u0e04\u0e32\u0e23_\u0e1e\u0e38\u0e18_\u0e1e\u0e24\u0e2b\u0e31\u0e2a_\u0e28\u0e38\u0e01\u0e23\u0e4c_\u0e40\u0e2a\u0e32\u0e23\u0e4c".split("_"),weekdaysMin:"\u0e2d\u0e32._\u0e08._\u0e2d._\u0e1e._\u0e1e\u0e24._\u0e28._\u0e2a.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY \u0e40\u0e27\u0e25\u0e32 H:mm",LLLL:"\u0e27\u0e31\u0e19dddd\u0e17\u0e35\u0e48 D MMMM YYYY \u0e40\u0e27\u0e25\u0e32 H:mm"},meridiemParse:/\u0e01\u0e48\u0e2d\u0e19\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07|\u0e2b\u0e25\u0e31\u0e07\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07/,isPM:function(e){return"\u0e2b\u0e25\u0e31\u0e07\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07"===e},meridiem:function(e,t,n){return e<12?"\u0e01\u0e48\u0e2d\u0e19\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07":"\u0e2b\u0e25\u0e31\u0e07\u0e40\u0e17\u0e35\u0e48\u0e22\u0e07"},calendar:{sameDay:"[\u0e27\u0e31\u0e19\u0e19\u0e35\u0e49 \u0e40\u0e27\u0e25\u0e32] LT",nextDay:"[\u0e1e\u0e23\u0e38\u0e48\u0e07\u0e19\u0e35\u0e49 \u0e40\u0e27\u0e25\u0e32] LT",nextWeek:"dddd[\u0e2b\u0e19\u0e49\u0e32 \u0e40\u0e27\u0e25\u0e32] LT",lastDay:"[\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e27\u0e32\u0e19\u0e19\u0e35\u0e49 \u0e40\u0e27\u0e25\u0e32] LT",lastWeek:"[\u0e27\u0e31\u0e19]dddd[\u0e17\u0e35\u0e48\u0e41\u0e25\u0e49\u0e27 \u0e40\u0e27\u0e25\u0e32] LT",sameElse:"L"},relativeTime:{future:"\u0e2d\u0e35\u0e01 %s",past:"%s\u0e17\u0e35\u0e48\u0e41\u0e25\u0e49\u0e27",s:"\u0e44\u0e21\u0e48\u0e01\u0e35\u0e48\u0e27\u0e34\u0e19\u0e32\u0e17\u0e35",ss:"%d \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35",m:"1 \u0e19\u0e32\u0e17\u0e35",mm:"%d \u0e19\u0e32\u0e17\u0e35",h:"1 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07",hh:"%d \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07",d:"1 \u0e27\u0e31\u0e19",dd:"%d \u0e27\u0e31\u0e19",w:"1 \u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c",ww:"%d \u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c",M:"1 \u0e40\u0e14\u0e37\u0e2d\u0e19",MM:"%d \u0e40\u0e14\u0e37\u0e2d\u0e19",y:"1 \u0e1b\u0e35",yy:"%d \u0e1b\u0e35"}})}(n("wd/R"))},EUcb:function(e,t,n){"use strict";t.a=function(e){return null!=e&&"object"==typeof e}},EY2u:function(e,t,n){"use strict";n.d(t,"a",(function(){return r})),n.d(t,"b",(function(){return s}));var i=n("HDdC");const r=new i.a(e=>e.complete());function s(e){return e?function(e){return new i.a(t=>e.schedule(()=>t.complete()))}(e):r}},EgGo:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("SVse"),r=n("sne2");class s{constructor(e){this.base=e}static concatURLSegments(e){return e.reduce(i.m.joinWithSlash)}static buildURL(e,...t){return s.concatURLSegments([...e?["/"]:[],...t])}getURL(e,t=!0,...n){return s.buildURL(t,this.base,e,...n)}getCreate(e=!0){return this.getURL(r.e.CREATE,e)}getCreateFrom(e,t=!0){return this.getURL(r.e.CREATE,t,e)}getDelete(e=!0){return this.getURL(r.e.DELETE,e)}getEdit(e,t=!0){return this.getURL(r.e.EDIT,t,e)}getUpdate(e,t=!0){return this.getURL(r.e.UPDATE,t,e)}getAdd(e=!0){return this.getURL(r.e.ADD,e)}getRemove(e=!0){return this.getURL(r.e.REMOVE,e)}getRecreate(e,t=!0){return this.getURL(r.e.RECREATE,t,e)}}},Ekvf:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("mrSG"),r=n("IheW"),s=n("lJxs"),o=n("xTzq"),a=n("o8EM"),c=n("8Y7J");let l=(()=>{let e=class{constructor(e,t){this.http=e,this.rbdConfigurationService=t,this.apiPath="api/pool"}create(e){return this.http.post(this.apiPath,e,{observe:"response"})}update(e){let t;return e.hasOwnProperty("srcpool")?(t=e.srcpool,delete e.srcpool):(t=e.pool,delete e.pool),this.http.put(`${this.apiPath}/${encodeURIComponent(t)}`,e,{observe:"response"})}delete(e){return this.http.delete(`${this.apiPath}/${e}`,{observe:"response"})}get(e){return this.http.get(`${this.apiPath}/${e}`)}getList(){return this.http.get(this.apiPath+"?stats=true")}getConfiguration(e){return this.http.get(`${this.apiPath}/${e}/configuration`).pipe(Object(s.a)(e=>e.map(e=>Object.assign(e,this.rbdConfigurationService.getOptionByName(e.name)))))}getInfo(){return this.http.get(`ui-${this.apiPath}/info`)}list(e=[]){const t=e.join(",");return this.http.get(`${this.apiPath}?attrs=${t}`).toPromise().then(e=>e)}};return e.\u0275fac=function(t){return new(t||e)(c.dc(r.b),c.dc(a.a))},e.\u0275prov=c.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e=Object(i.b)([o.a,Object(i.d)("design:paramtypes",[r.b,a.a])],e),e})()},EmSq:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("8Y7J"),r=n("LvDl"),s=n.n(r),o=n("Fgil"),a=n("aXbf"),c=n("s7LF");let l=(()=>{class e{constructor(e,t,n,r){this.elementRef=e,this.control=t,this.dimlessBinaryPipe=n,this.formatter=r,this.ngModelChange=new i.o,this.el=this.elementRef.nativeElement}ngOnInit(){this.setValue(this.el.value)}setValue(e){/^[\d.]+$/.test(e)&&(e+=this.defaultUnit||"m");const t=this.formatter.toBytes(e),n=this.round(t);this.el.value=this.dimlessBinaryPipe.transform(n),null!==t?(this.ngModelChange.emit(this.el.value),this.control.control.setValue(this.el.value)):(this.ngModelChange.emit(null),this.control.control.setValue(null))}round(e){if(null!==e&&0!==e){if(!s.a.isUndefined(this.minBytes)&&ethis.maxBytes)return this.maxBytes;if(!s.a.isUndefined(this.roundPower)){const t=Math.round(Math.log(e)/Math.log(this.roundPower));return Math.pow(this.roundPower,t)}}return e}onBlur(e){this.setValue(e)}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m),i.Mb(c.p),i.Mb(o.a),i.Mb(a.a))},e.\u0275dir=i.Hb({type:e,selectors:[["","cdDimlessBinary",""]],hostBindings:function(e,t){1&e&&i.gc("blur",(function(e){return t.onBlur(e.target.value)}))},inputs:{minBytes:"minBytes",maxBytes:"maxBytes",roundPower:"roundPower",defaultUnit:"defaultUnit"},outputs:{ngModelChange:"ngModelChange"}}),e})()},F8JR:function(e,t,n){"use strict";var i=n("tycR").forEach,r=n("pkCn")("forEach");e.exports=r?[].forEach:function(e){return i(this,e,arguments.length>1?arguments[1]:void 0)}},FFMq:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){return e.join(", ")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"join",type:e,pure:!0}),e})()},FMNM:function(e,t,n){var i=n("xrYK"),r=n("kmMV");e.exports=function(e,t){var n=e.exec;if("function"==typeof n){var s=n.call(e,t);if("object"!=typeof s)throw TypeError("RegExp exec method returned something other than an Object or null");return s}if("RegExp"!==i(e))throw TypeError("RegExp#exec called on incompatible receiver");return r.call(e,t)}},FSuO:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("8Y7J"),r=n("LvDl"),s=n.n(r),o=n("x38r"),a=n("a0VL"),c=n("uIqm");let l=(()=>{class e{constructor(e){this.datePipe=e,this.autoReload=5e3,this.renderObjects=!1,this.appendParentKey=!0,this.hideEmpty=!1,this.hideKeys=[],this.columns=[],this.fetchData=new i.o}ngOnInit(){this.columns=[{prop:"key",flexGrow:1,cellTransformation:o.a.bold},{prop:"value",flexGrow:3}],this.customCss&&(this.columns[1].cellTransformation=o.a.classAdding),this.fetchData.observers.length>0&&this.table.fetchData.subscribe(()=>{this.fetchData.emit()}),this.useData()}ngOnChanges(){this.useData()}useData(){if(!this.data)return;let e=this.makePairs(this.data);this.hideKeys&&(e=e.filter(e=>!this.hideKeys.includes(e.key))),this.tableData=e}makePairs(e){let t=[];if(e){if(s.a.isArray(e))t=this.makePairsFromArray(e);else{if(!s.a.isObject(e))throw new Error("Wrong data format");t=this.makePairsFromObject(e)}return t=t.map(e=>(e.value=this.convertValue(e.value),e)).filter(e=>null!==e.value),s.a.sortBy(this.renderObjects?this.insertFlattenObjects(t):t,"key")}}makePairsFromArray(e){let t=[];const n=e[0];if(s.a.isArray(n)){if(2!==n.length)throw new Error(`Array contains too many elements (${n.length}). Needs to be of type [string, any][]`);t=e.map(e=>({key:e[0],value:e[1]}))}else s.a.isObject(n)&&(t=s.a.has(n,"key")&&s.a.has(n,"value")?[...e]:e.reduce((e,t)=>e.concat(this.makePairsFromObject(t)),t));return t}makePairsFromObject(e){return Object.keys(e).map(t=>({key:t,value:e[t]}))}insertFlattenObjects(e){return s.a.flattenDeep(e.map(e=>{const t=e.value,n=s.a.isObject(t);return!n||s.a.isEmpty(t)?(n&&(e.value=""),e):this.splitItemIntoItems(e)}))}splitItemIntoItems(e){return this.makePairs(e.value).map(t=>(this.appendParentKey&&(t.key=e.key+" "+t.key),t))}convertValue(e){if(s.a.isArray(e)){if(s.a.isEmpty(e)&&this.hideEmpty)return null;e=e.map(e=>s.a.isObject(e)?JSON.stringify(e):e).join(", ")}else if(s.a.isObject(e)){if(this.hideEmpty&&s.a.isEmpty(e)||!this.renderObjects)return null}else if(s.a.isString(e)){if(""===e&&this.hideEmpty)return null;this.isDate(e)&&(e=this.datePipe.transform(e)||e)}return e}isDate(e){const t="[ -:.TZ]",n="\\d{2}"+t;return e.match(new RegExp("^\\d{4}"+t+n+n+n+n+n+"\\d*Z?$"))}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(a.a))},e.\u0275cmp=i.Gb({type:e,selectors:[["cd-table-key-value"]],viewQuery:function(e,t){var n;1&e&&i.Jc(c.a,!0),2&e&&i.zc(n=i.hc())&&(t.table=n.first)},inputs:{data:"data",autoReload:"autoReload",renderObjects:"renderObjects",appendParentKey:"appendParentKey",hideEmpty:"hideEmpty",hideKeys:"hideKeys",customCss:"customCss"},outputs:{fetchData:"fetchData"},features:[i.wb],decls:2,vars:9,consts:[["columnMode","flex",3,"data","columns","toolHeader","autoReload","customCss","autoSave","header","footer","limit"],["table",""]],template:function(e,t){1&e&&i.Nb(0,"cd-table",0,1),2&e&&i.pc("data",t.tableData)("columns",t.columns)("toolHeader",!1)("autoReload",t.autoReload)("customCss",t.customCss)("autoSave",!1)("header",!1)("footer",!1)("limit",0)},directives:[c.a],styles:[""]}),e})()},Fgil:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("aXbf"),r=n("8Y7J");let s=(()=>{class e{constructor(e){this.formatter=e}transform(e){return this.formatter.format_number(e,1024,["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"])}}return e.\u0275fac=function(t){return new(t||e)(r.Mb(i.a))},e.\u0275pipe=r.Lb({name:"dimlessBinary",type:e,pure:!0}),e})()},Fnuy:function(e,t,n){!function(e){"use strict";e.defineLocale("oc-lnc",{months:{standalone:"geni\xe8r_febri\xe8r_mar\xe7_abril_mai_junh_julhet_agost_setembre_oct\xf2bre_novembre_decembre".split("_"),format:"de geni\xe8r_de febri\xe8r_de mar\xe7_d'abril_de mai_de junh_de julhet_d'agost_de setembre_d'oct\xf2bre_de novembre_de decembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._mar\xe7_abr._mai_junh_julh._ago._set._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"dimenge_diluns_dimars_dim\xe8cres_dij\xf2us_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dm._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dm_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:"[u\xe8i a] LT",nextDay:"[deman a] LT",nextWeek:"dddd [a] LT",lastDay:"[i\xe8r a] LT",lastWeek:"dddd [passat a] LT",sameElse:"L"},relativeTime:{future:"d'aqu\xed %s",past:"fa %s",s:"unas segondas",ss:"%d segondas",m:"una minuta",mm:"%d minutas",h:"una ora",hh:"%d oras",d:"un jorn",dd:"%d jorns",M:"un mes",MM:"%d meses",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|\xe8|a)/,ordinal:function(e,t){var n=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"\xe8";return"w"!==t&&"W"!==t||(n="a"),e+n},week:{dow:1,doy:4}})}(n("wd/R"))},"G+Rx":function(e,t,n){var i=n("0GbY");e.exports=i("document","documentElement")},G0Uy:function(e,t,n){!function(e){"use strict";e.defineLocale("mt",{months:"Jannar_Frar_Marzu_April_Mejju_\u0120unju_Lulju_Awwissu_Settembru_Ottubru_Novembru_Di\u010bembru".split("_"),monthsShort:"Jan_Fra_Mar_Apr_Mej_\u0120un_Lul_Aww_Set_Ott_Nov_Di\u010b".split("_"),weekdays:"Il-\u0126add_It-Tnejn_It-Tlieta_L-Erbg\u0127a_Il-\u0126amis_Il-\u0120img\u0127a_Is-Sibt".split("_"),weekdaysShort:"\u0126ad_Tne_Tli_Erb_\u0126am_\u0120im_Sib".split("_"),weekdaysMin:"\u0126a_Tn_Tl_Er_\u0126a_\u0120i_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Illum fil-]LT",nextDay:"[G\u0127ada fil-]LT",nextWeek:"dddd [fil-]LT",lastDay:"[Il-biera\u0127 fil-]LT",lastWeek:"dddd [li g\u0127adda] [fil-]LT",sameElse:"L"},relativeTime:{future:"f\u2019 %s",past:"%s ilu",s:"ftit sekondi",ss:"%d sekondi",m:"minuta",mm:"%d minuti",h:"sieg\u0127a",hh:"%d sieg\u0127at",d:"\u0121urnata",dd:"%d \u0121ranet",M:"xahar",MM:"%d xhur",y:"sena",yy:"%d sni"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:1,doy:4}})}(n("wd/R"))},G0yt:function(e,t,n){"use strict";n.d(t,"a",(function(){return Xt})),n.d(t,"b",(function(){return He})),n.d(t,"c",(function(){return We})),n.d(t,"d",(function(){return Qe})),n.d(t,"e",(function(){return Ve})),n.d(t,"f",(function(){return Be})),n.d(t,"g",(function(){return ht})),n.d(t,"h",(function(){return Nt})),n.d(t,"i",(function(){return Bt})),n.d(t,"j",(function(){return $t})),n.d(t,"k",(function(){return Ht})),n.d(t,"l",(function(){return Ut})),n.d(t,"m",(function(){return Vt})),n.d(t,"n",(function(){return It})),n.d(t,"o",(function(){return sn})),n.d(t,"p",(function(){return dn})),n.d(t,"q",(function(){return ln})),n.d(t,"r",(function(){return un})),n.d(t,"s",(function(){return hn})),n.d(t,"t",(function(){return pn})),n.d(t,"u",(function(){return fn})),n.d(t,"v",(function(){return zt})),n.d(t,"w",(function(){return Sn})),n.d(t,"x",(function(){return yn})),n.d(t,"y",(function(){return Mn})),n.d(t,"z",(function(){return kn})),n.d(t,"A",(function(){return Dn})),n.d(t,"B",(function(){return jn})),n.d(t,"C",(function(){return Nn})),n.d(t,"D",(function(){return $n})),n.d(t,"E",(function(){return Fn})),n.d(t,"F",(function(){return Hn})),n.d(t,"G",(function(){return Kn})),n.d(t,"H",(function(){return Zn}));var i=n("8Y7J"),r=n("SVse"),s=n("s7LF"),o=n("XNiG"),a=n("2Vo4"),c=(n("itXk"),n("PqYM"),n("5yfJ"),n("xgIS")),l=n("VRyK"),u=n("DH7j"),d=n("yCtX"),h=n("l7GE"),f=n("ZUHj");class p{call(e,t){return t.subscribe(new m(e))}}class m extends h.a{constructor(e){super(e),this.hasFirst=!1,this.observables=[],this.subscriptions=[]}_next(e){this.observables.push(e)}_complete(){const e=this.observables,t=e.length;if(0===t)this.destination.complete();else{for(let n=0;n{let n;return"function"==typeof e[e.length-1]&&(n=e.pop()),t.lift(new x(e,n))}}class x{constructor(e,t){this.observables=e,this.project=t}call(e,t){return t.subscribe(new k(e,this.observables,this.project))}}class k extends h.a{constructor(e,t,n){super(e),this.observables=t,this.project=n,this.toRespond=[];const i=t.length;this.values=new Array(i);for(let r=0;r0){const e=i.indexOf(n);-1!==e&&i.splice(e,1)}}notifyComplete(){}_next(e){if(0===this.toRespond.length){const t=[e,...this.values];this.project?this._tryProject(t):this.destination.next(t)}}_tryProject(e){let t;try{t=this.project.apply(this,e)}catch(n){return void this.destination.error(n)}this.destination.next(t)}}var D=n("3E0/"),T=n("w1tV");function C(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",1),i.Yb(1,2),i.gc("click",(function(){return i.Dc(e),i.ic().closeHandler()})),i.Sb(2,"span",3),i.Oc(3,"\xd7"),i.Rb(),i.Rb()}}const O=["*"],L=["defaultDayTemplate"],R=["content"];function E(e,t){if(1&e&&i.Nb(0,"div",7),2&e){const e=t.currentMonth,n=t.selected,r=t.disabled,s=t.focused;i.pc("date",t.date)("currentMonth",e)("selected",n)("disabled",r)("focused",s)}}function A(e,t){if(1&e&&(i.Sb(0,"div",12),i.Oc(1),i.Rb()),2&e){const e=i.ic().$implicit,t=i.ic(2);i.yb(1),i.Rc(" ",t.i18n.getMonthFullName(e.number,e.year)," ",t.i18n.getYearNumerals(e.year)," ")}}function I(e,t){if(1&e&&(i.Sb(0,"div",9),i.Mc(1,A,2,2,"div",10),i.Nb(2,"ngb-datepicker-month",11),i.Rb()),2&e){const e=t.$implicit,n=i.ic(2);i.yb(1),i.pc("ngIf","none"===n.navigation||n.displayMonths>1&&"select"===n.navigation),i.yb(1),i.pc("month",e.firstDate)}}function P(e,t){if(1&e&&i.Mc(0,I,3,2,"div",8),2&e){const e=i.ic();i.pc("ngForOf",e.model.months)}}function j(e,t){if(1&e){const e=i.Tb();i.Sb(0,"ngb-datepicker-navigation",13),i.gc("navigate",(function(t){return i.Dc(e),i.ic().onNavigateEvent(t)}))("select",(function(t){return i.Dc(e),i.ic().onNavigateDateSelect(t)})),i.Rb()}if(2&e){const e=i.ic();i.pc("date",e.model.firstDate)("months",e.model.months)("disabled",e.model.disabled)("showSelect","select"===e.model.navigation)("prevDisabled",e.model.prevDisabled)("nextDisabled",e.model.nextDisabled)("selectBoxes",e.model.selectBoxes)}}function N(e,t){}function F(e,t){}function Y(e,t){1&e&&i.Nb(0,"div",5)}function z(e,t){if(1&e&&(i.Sb(0,"div",6),i.Oc(1),i.Rb()),2&e){const e=t.$implicit,n=i.ic(2);i.yb(1),i.Qc(" ",n.i18n.getWeekdayShortName(e)," ")}}function $(e,t){if(1&e&&(i.Sb(0,"div",2),i.Mc(1,Y,1,0,"div",3),i.Mc(2,z,2,1,"div",4),i.Rb()),2&e){const e=i.ic();i.yb(1),i.pc("ngIf",e.datepicker.showWeekNumbers),i.yb(1),i.pc("ngForOf",e.viewModel.weekdays)}}function H(e,t){if(1&e&&(i.Sb(0,"div",11),i.Oc(1),i.Rb()),2&e){const e=i.ic(2).$implicit,t=i.ic();i.yb(1),i.Pc(t.i18n.getWeekNumerals(e.number))}}function W(e,t){}function V(e,t){if(1&e&&i.Mc(0,W,0,0,"ng-template",14),2&e){const e=i.ic().$implicit,t=i.ic(3);i.pc("ngTemplateOutlet",t.datepicker.dayTemplate)("ngTemplateOutletContext",e.context)}}function B(e,t){if(1&e){const e=i.Tb();i.Sb(0,"div",12),i.gc("click",(function(n){i.Dc(e);const r=t.$implicit;return i.ic(3).doSelect(r),n.preventDefault()})),i.Mc(1,V,1,2,"ng-template",13),i.Rb()}if(2&e){const e=t.$implicit;i.Eb("disabled",e.context.disabled)("hidden",e.hidden)("ngb-dp-today",e.context.today),i.pc("tabindex",e.tabindex),i.zb("aria-label",e.ariaLabel),i.yb(1),i.pc("ngIf",!e.hidden)}}function U(e,t){if(1&e&&(i.Sb(0,"div",8),i.Mc(1,H,2,1,"div",9),i.Mc(2,B,2,9,"div",10),i.Rb()),2&e){const e=i.ic().$implicit,t=i.ic();i.yb(1),i.pc("ngIf",t.datepicker.showWeekNumbers),i.yb(1),i.pc("ngForOf",e.days)}}function q(e,t){1&e&&i.Mc(0,U,3,2,"div",7),2&e&&i.pc("ngIf",!t.$implicit.collapsed)}function G(e,t){if(1&e){const e=i.Tb();i.Sb(0,"ngb-datepicker-navigation-select",8),i.gc("select",(function(t){return i.Dc(e),i.ic().select.emit(t)})),i.Rb()}if(2&e){const e=i.ic();i.pc("date",e.date)("disabled",e.disabled)("months",e.selectBoxes.months)("years",e.selectBoxes.years)}}function J(e,t){1&e&&i.Nb(0,"div",0)}function Q(e,t){1&e&&i.Nb(0,"div",0)}function K(e,t){if(1&e&&(i.Mc(0,J,1,0,"div",10),i.Sb(1,"div",11),i.Oc(2),i.Rb(),i.Mc(3,Q,1,0,"div",10)),2&e){const e=t.$implicit,n=t.index,r=i.ic(2);i.pc("ngIf",n>0),i.yb(2),i.Rc(" ",r.i18n.getMonthFullName(e.number,e.year)," ",r.i18n.getYearNumerals(e.year)," "),i.yb(1),i.pc("ngIf",n!==r.months.length-1)}}function Z(e,t){if(1&e&&i.Mc(0,K,4,4,"ng-template",9),2&e){const e=i.ic();i.pc("ngForOf",e.months)}}const X=["ngbDatepickerDayView",""],ee=["month"],te=["year"];function ne(e,t){if(1&e&&(i.Sb(0,"option",6),i.Oc(1),i.Rb()),2&e){const e=t.$implicit,n=i.ic();i.pc("value",e),i.zb("aria-label",n.i18n.getMonthFullName(e,null==n.date?null:n.date.year)),i.yb(1),i.Pc(n.i18n.getMonthShortName(e,null==n.date?null:n.date.year))}}function ie(e,t){if(1&e&&(i.Sb(0,"option",6),i.Oc(1),i.Rb()),2&e){const e=t.$implicit,n=i.ic();i.pc("value",e),i.yb(1),i.Pc(n.i18n.getYearNumerals(e))}}const re=["dialog"],se=["ngbNavOutlet",""];function oe(e,t){}const ae=function(e){return{$implicit:e}};function ce(e,t){if(1&e&&(i.Sb(0,"div",2),i.Mc(1,oe,0,0,"ng-template",3),i.Rb()),2&e){const e=i.ic().$implicit,t=i.ic();i.Eb("active",e.active),i.pc("id",e.panelDomId),i.zb("role",t.paneRole?t.paneRole:t.nav.roles?"tabpanel":void 0)("aria-labelledby",e.domId),i.yb(1),i.pc("ngTemplateOutlet",(null==e.contentTpl?null:e.contentTpl.templateRef)||null)("ngTemplateOutletContext",i.uc(7,ae,e.active))}}function le(e,t){1&e&&i.Mc(0,ce,2,9,"div",1),2&e&&i.pc("ngIf",t.$implicit.isPanelInDom())}function ue(e,t){if(1&e&&i.Oc(0),2&e){const e=i.ic(2);i.Pc(e.title)}}function de(e,t){}function he(e,t){if(1&e&&(i.Sb(0,"h3",3),i.Mc(1,ue,1,1,"ng-template",null,4,i.Nc),i.Mc(3,de,0,0,"ng-template",5),i.Rb()),2&e){const e=i.Ac(2),t=i.ic();i.yb(3),i.pc("ngTemplateOutlet",t.isTitleTemplate()?t.title:e)("ngTemplateOutletContext",t.context)}}function fe(e,t){if(1&e&&(i.Sb(0,"span"),i.Wb(1,3),i.jc(2,"percent"),i.Rb()),2&e){const e=i.ic();i.yb(2),i.ac(i.kc(2,1,e.getValue()/e.max)),i.Xb(1)}}function pe(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",12),i.gc("click",(function(){i.Dc(e);const t=i.ic();return t.changeHour(t.hourStep)})),i.Nb(1,"span",13),i.Sb(2,"span",14),i.Wb(3,15),i.Rb(),i.Rb()}if(2&e){const e=i.ic();i.Eb("btn-sm",e.isSmallSize)("btn-lg",e.isLargeSize)("disabled",e.disabled),i.pc("disabled",e.disabled)}}function me(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",12),i.gc("click",(function(){i.Dc(e);const t=i.ic();return t.changeHour(-t.hourStep)})),i.Nb(1,"span",16),i.Sb(2,"span",14),i.Wb(3,17),i.Rb(),i.Rb()}if(2&e){const e=i.ic();i.Eb("btn-sm",e.isSmallSize)("btn-lg",e.isLargeSize)("disabled",e.disabled),i.pc("disabled",e.disabled)}}function be(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",12),i.gc("click",(function(){i.Dc(e);const t=i.ic();return t.changeMinute(t.minuteStep)})),i.Nb(1,"span",13),i.Sb(2,"span",14),i.Wb(3,18),i.Rb(),i.Rb()}if(2&e){const e=i.ic();i.Eb("btn-sm",e.isSmallSize)("btn-lg",e.isLargeSize)("disabled",e.disabled),i.pc("disabled",e.disabled)}}function ge(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",12),i.gc("click",(function(){i.Dc(e);const t=i.ic();return t.changeMinute(-t.minuteStep)})),i.Nb(1,"span",16),i.Sb(2,"span",14),i.Wb(3,19),i.Rb(),i.Rb()}if(2&e){const e=i.ic();i.Eb("btn-sm",e.isSmallSize)("btn-lg",e.isLargeSize)("disabled",e.disabled),i.pc("disabled",e.disabled)}}function _e(e,t){1&e&&(i.Sb(0,"div",6),i.Oc(1,":"),i.Rb())}function ye(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",12),i.gc("click",(function(){i.Dc(e);const t=i.ic(2);return t.changeSecond(t.secondStep)})),i.Nb(1,"span",13),i.Sb(2,"span",14),i.Wb(3,22),i.Rb(),i.Rb()}if(2&e){const e=i.ic(2);i.Eb("btn-sm",e.isSmallSize)("btn-lg",e.isLargeSize)("disabled",e.disabled),i.pc("disabled",e.disabled)}}function ve(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",12),i.gc("click",(function(){i.Dc(e);const t=i.ic(2);return t.changeSecond(-t.secondStep)})),i.Nb(1,"span",16),i.Sb(2,"span",14),i.Wb(3,23),i.Rb(),i.Rb()}if(2&e){const e=i.ic(2);i.Eb("btn-sm",e.isSmallSize)("btn-lg",e.isLargeSize)("disabled",e.disabled),i.pc("disabled",e.disabled)}}function we(e,t){if(1&e){const e=i.Tb();i.Sb(0,"div",20),i.Mc(1,ye,4,7,"button",3),i.Sb(2,"input",4),i.Yb(3,21),i.gc("change",(function(t){return i.Dc(e),i.ic().updateSecond(t.target.value)}))("input",(function(t){return i.Dc(e),i.ic().formatInput(t.target)}))("keydown.ArrowUp",(function(t){i.Dc(e);const n=i.ic();return n.changeSecond(n.secondStep),t.preventDefault()}))("keydown.ArrowDown",(function(t){i.Dc(e);const n=i.ic();return n.changeSecond(-n.secondStep),t.preventDefault()})),i.Rb(),i.Mc(4,ve,4,7,"button",3),i.Rb()}if(2&e){const e=i.ic();i.yb(1),i.pc("ngIf",e.spinners),i.yb(1),i.Eb("form-control-sm",e.isSmallSize)("form-control-lg",e.isLargeSize),i.pc("value",e.formatMinSec(null==e.model?null:e.model.second))("readOnly",e.readonlyInputs)("disabled",e.disabled),i.yb(2),i.pc("ngIf",e.spinners)}}function Se(e,t){1&e&&i.Nb(0,"div",6)}function Me(e,t){if(1&e&&(i.Qb(0),i.Wb(1,28),i.Pb()),2&e){const e=i.ic(2);i.yb(1),i.ac(e.i18n.getAfternoonPeriod()),i.Xb(1)}}function xe(e,t){if(1&e&&i.Wb(0,29),2&e){const e=i.ic(2);i.ac(e.i18n.getMorningPeriod()),i.Xb(0)}}function ke(e,t){if(1&e){const e=i.Tb();i.Sb(0,"div",24),i.Sb(1,"button",25),i.gc("click",(function(){return i.Dc(e),i.ic().toggleMeridian()})),i.Mc(2,Me,2,1,"ng-container",26),i.Mc(3,xe,1,1,"ng-template",null,27,i.Nc),i.Rb(),i.Rb()}if(2&e){const e=i.Ac(4),t=i.ic();i.yb(1),i.Eb("btn-sm",t.isSmallSize)("btn-lg",t.isLargeSize)("disabled",t.disabled),i.pc("disabled",t.disabled),i.yb(1),i.pc("ngIf",t.model&&t.model.hour>=12)("ngIfElse",e)}}function De(e,t){if(1&e&&(i.Sb(0,"span"),i.Oc(1),i.Rb()),2&e){const e=i.ic().$implicit,t=i.ic();i.Ab(t.highlightClass),i.yb(1),i.Pc(e)}}function Te(e,t){if(1&e&&i.Oc(0),2&e){const e=i.ic().$implicit;i.Pc(e)}}function Ce(e,t){if(1&e&&(i.Mc(0,De,2,3,"span",1),i.Mc(1,Te,1,1,"ng-template",null,2,i.Nc)),2&e){const e=t.odd,n=i.Ac(2);i.pc("ngIf",e)("ngIfElse",n)}}function Oe(e,t){if(1&e&&i.Nb(0,"ngb-highlight",2),2&e){const e=t.term;i.pc("result",(0,t.formatter)(t.result))("term",e)}}function Le(e,t){}const Re=function(e,t,n){return{result:e,term:t,formatter:n}};function Ee(e,t){if(1&e){const e=i.Tb();i.Sb(0,"button",3),i.gc("mouseenter",(function(){i.Dc(e);const n=t.index;return i.ic().markActive(n)}))("click",(function(){i.Dc(e);const n=t.$implicit;return i.ic().select(n)})),i.Mc(1,Le,0,0,"ng-template",4),i.Rb()}if(2&e){const e=t.$implicit,n=t.index,r=i.ic(),s=i.Ac(1);i.Eb("active",n===r.activeIdx),i.pc("id",r.id+"-"+n),i.yb(1),i.pc("ngTemplateOutlet",r.resultTemplate||s)("ngTemplateOutletContext",i.wc(5,Re,e,r.term,r.formatter))}}function Ae(e){return parseInt(""+e,10)}function Ie(e){return null!=e?""+e:""}function Pe(e){return"string"==typeof e}function je(e){return!isNaN(Ae(e))}function Ne(e){return"number"==typeof e&&isFinite(e)&&Math.floor(e)===e}function Fe(e){return null!=e}function Ye(e){return je(e)?("0"+e).slice(-2):""}function ze(e,t){return e&&e.className&&e.className.split&&e.className.split(/\s+/).indexOf(t)>=0}"undefined"==typeof Element||Element.prototype.closest||(Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),Element.prototype.closest=function(e){let t=this;if(!document.documentElement.contains(t))return null;do{if(t.matches(e))return t;t=t.parentElement||t.parentNode}while(null!==t&&1===t.nodeType);return null});let $e=(()=>{let e=class{constructor(){this.dismissible=!0,this.type="warning"}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})(),He=(()=>{let e=class{constructor(e,t,n){this._renderer=t,this._element=n,this.close=new i.o,this.dismissible=e.dismissible,this.type=e.type}closeHandler(){this.close.emit()}ngOnChanges(e){const t=e.type;t&&!t.firstChange&&(this._renderer.removeClass(this._element.nativeElement,"alert-"+t.previousValue),this._renderer.addClass(this._element.nativeElement,"alert-"+t.currentValue))}ngOnInit(){this._renderer.addClass(this._element.nativeElement,"alert-"+this.type)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb($e),i.Mb(i.E),i.Mb(i.m))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-alert"]],hostAttrs:["role","alert",1,"alert"],hostVars:2,hostBindings:function(e,t){2&e&&i.Eb("alert-dismissible",t.dismissible)},inputs:{dismissible:"dismissible",type:"type"},outputs:{close:"close"},features:[i.wb],ngContentSelectors:O,decls:2,vars:1,consts:function(){return[["type","button","class","close",3,"click",4,"ngIf",6,"aria-label"],["type","button",1,"close",3,"click",6,"aria-label"],["aria-label","Close"],["aria-hidden","true"]]},template:function(e,t){1&e&&(i.oc(),i.nc(0),i.Mc(1,C,4,0,"button",0)),2&e&&(i.yb(1),i.pc("ngIf",t.dismissible))},directives:[r.r],styles:["ngb-alert{display:block}"],encapsulation:2,changeDetection:0}),e})(),We=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c]]}),e})(),Ve=(()=>{let e=class{constructor(){this.collapsed=!1}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbCollapse",""]],hostVars:4,hostBindings:function(e,t){2&e&&i.Eb("collapse",!0)("show",!t.collapsed)},inputs:{collapsed:["ngbCollapse","collapsed"]},exportAs:["ngbCollapse"]}),e})(),Be=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)}}),e})();class Ue{constructor(e,t,n){this.year=Ne(e)?e:null,this.month=Ne(t)?t:null,this.day=Ne(n)?n:null}static from(e){return e instanceof Ue?e:e?new Ue(e.year,e.month,e.day):null}equals(e){return null!=e&&this.year===e.year&&this.month===e.month&&this.day===e.day}before(e){return!!e&&(this.year===e.year?this.month===e.month?this.day!==e.day&&this.daye.day:this.month>e.month:this.year>e.year)}}function qe(e){return new Ue(e.getFullYear(),e.getMonth()+1,e.getDate())}function Ge(e){const t=new Date(e.year,e.month-1,e.day,12);return isNaN(t.getTime())||t.setFullYear(e.year),t}function Je(){return new Ke}let Qe=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:Je,token:e,providedIn:"root"}),e})(),Ke=(()=>{let e=class extends Qe{getDaysPerWeek(){return 7}getMonths(){return[1,2,3,4,5,6,7,8,9,10,11,12]}getWeeksPerMonth(){return 6}getNext(e,t="d",n=1){let i=Ge(e),r=!0,s=i.getMonth();switch(t){case"y":i.setFullYear(i.getFullYear()+n);break;case"m":s+=n,i.setMonth(s),s%=12,s<0&&(s+=12);break;case"d":i.setDate(i.getDate()+n),r=!1;break;default:return e}return r&&i.getMonth()!==s&&i.setDate(0),qe(i)}getPrev(e,t="d",n=1){return this.getNext(e,t,-n)}getWeekday(e){let t=Ge(e).getDay();return 0===t?7:t}getWeekNumber(e,t){7===t&&(t=0);const n=Ge(e[(11-t)%7]);n.setDate(n.getDate()+4-(n.getDay()||7));const i=n.getTime();return n.setMonth(0),n.setDate(1),Math.floor(Math.round((i-n.getTime())/864e5)/7)+1}getToday(){return qe(new Date)}isValid(e){if(!(e&&Ne(e.year)&&Ne(e.month)&&Ne(e.day)))return!1;if(0===e.year)return!1;const t=Ge(e);return!isNaN(t.getTime())&&t.getFullYear()===e.year&&t.getMonth()+1===e.month&&t.getDate()===e.day}};return e.\u0275fac=function(t){return Xn(t||e)},e.\u0275prov=i.Ib({token:e,factory:function(t){return e.\u0275fac(t)}}),e})();function Ze(e,t){return!function(e,t){return!e&&!t||!!e&&!!t&&e.equals(t)}(e,t)}function Xe(e,t){return!(!e&&!t||e&&t&&e.year===t.year&&e.month===t.month)}function et(e,t,n){return e&&t&&e.before(t)?t:e&&n&&e.after(n)?n:e||null}function tt(e,t){const{minDate:n,maxDate:i,disabled:r,markDisabled:s}=t;return!(null==e||r||s&&s(e,{year:e.year,month:e.month})||n&&e.before(n)||i&&e.after(i))}let nt=(()=>{let e=class{getDayNumerals(e){return""+e.day}getWeekNumerals(e){return""+e}getYearNumerals(e){return""+e}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return e=Object(i.dc)(i.v),new it(e);var e},token:e,providedIn:"root"}),e})(),it=(()=>{let e=class extends nt{constructor(e){super(),this._locale=e;const t=Object(r.F)(e,r.g.Standalone,r.B.Short);this._weekdaysShort=t.map((e,n)=>t[(n+1)%7]),this._monthsShort=Object(r.H)(e,r.g.Standalone,r.B.Abbreviated),this._monthsFull=Object(r.H)(e,r.g.Standalone,r.B.Wide)}getWeekdayShortName(e){return this._weekdaysShort[e-1]||""}getMonthShortName(e){return this._monthsShort[e-1]||""}getMonthFullName(e){return this._monthsFull[e-1]||""}getDayAriaLabel(e){const t=new Date(e.year,e.month-1,e.day);return Object(r.E)(t,"fullDate",this._locale)}};return e.\u0275fac=function(t){return new(t||e)(i.dc(i.v))},e.\u0275prov=i.Ib({token:e,factory:function(t){return e.\u0275fac(t)}}),e})(),rt=(()=>{let e=class{constructor(e,t){this._calendar=e,this._i18n=t,this._VALIDATORS={dayTemplateData:e=>{if(this._state.dayTemplateData!==e)return{dayTemplateData:e}},displayMonths:e=>{if(Ne(e=Ae(e))&&e>0&&this._state.displayMonths!==e)return{displayMonths:e}},disabled:e=>{if(this._state.disabled!==e)return{disabled:e}},firstDayOfWeek:e=>{if(Ne(e=Ae(e))&&e>=0&&this._state.firstDayOfWeek!==e)return{firstDayOfWeek:e}},focusVisible:e=>{if(this._state.focusVisible!==e&&!this._state.disabled)return{focusVisible:e}},markDisabled:e=>{if(this._state.markDisabled!==e)return{markDisabled:e}},maxDate:e=>{const t=this.toValidDate(e,null);if(Ze(this._state.maxDate,t))return{maxDate:t}},minDate:e=>{const t=this.toValidDate(e,null);if(Ze(this._state.minDate,t))return{minDate:t}},navigation:e=>{if(this._state.navigation!==e)return{navigation:e}},outsideDays:e=>{if(this._state.outsideDays!==e)return{outsideDays:e}}},this._model$=new o.a,this._dateSelect$=new o.a,this._state={dayTemplateData:null,markDisabled:null,maxDate:null,minDate:null,disabled:!1,displayMonths:1,firstDate:null,firstDayOfWeek:1,lastDate:null,focusDate:null,focusVisible:!1,months:[],navigation:"select",outsideDays:"visible",prevDisabled:!1,nextDisabled:!1,selectedDate:null,selectBoxes:{years:[],months:[]}}}get model$(){return this._model$.pipe(Object(v.a)(e=>e.months.length>0))}get dateSelect$(){return this._dateSelect$.pipe(Object(v.a)(e=>null!==e))}set(e){let t=Object.keys(e).map(t=>this._VALIDATORS[t](e[t])).reduce((e,t)=>Object.assign(Object.assign({},e),t),{});Object.keys(t).length>0&&this._nextState(t)}focus(e){const t=this.toValidDate(e,null);null!=t&&!this._state.disabled&&Ze(this._state.focusDate,t)&&this._nextState({focusDate:e})}focusSelect(){tt(this._state.focusDate,this._state)&&this.select(this._state.focusDate,{emitEvent:!0})}open(e){const t=this.toValidDate(e,this._calendar.getToday());null==t||this._state.disabled||this._state.firstDate&&!Xe(this._state.firstDate,t)||this._nextState({firstDate:t})}select(e,t={}){const n=this.toValidDate(e,null);null==n||this._state.disabled||(Ze(this._state.selectedDate,n)&&this._nextState({selectedDate:n}),t.emitEvent&&tt(n,this._state)&&this._dateSelect$.next(n))}toValidDate(e,t){const n=Ue.from(e);return void 0===t&&(t=this._calendar.getToday()),this._calendar.isValid(n)?n:t}getMonth(e){for(let t of this._state.months)if(e.month===t.number&&e.year===t.year)return t;throw new Error(`month ${e.month} of year ${e.year} not found`)}_nextState(e){const t=this._updateState(e);this._patchContexts(t),this._state=t,this._model$.next(this._state)}_patchContexts(e){const{months:t,displayMonths:n,selectedDate:i,focusDate:r,focusVisible:s,disabled:o,outsideDays:a}=e;e.months.forEach(e=>{e.weeks.forEach(c=>{c.days.forEach(c=>{r&&(c.context.focused=r.equals(c.date)&&s),c.tabindex=!o&&r&&c.date.equals(r)&&r.month===e.number?0:-1,!0===o&&(c.context.disabled=!0),void 0!==i&&(c.context.selected=null!==i&&i.equals(c.date)),e.number!==c.date.month&&(c.hidden="hidden"===a||"collapsed"===a||n>1&&c.date.after(t[0].firstDate)&&c.date.before(t[n-1].lastDate))})})})}_updateState(e){const t=Object.assign({},this._state,e);let n=t.firstDate;if(("minDate"in e||"maxDate"in e)&&(function(e,t){if(t&&e&&t.before(e))throw new Error(`'maxDate' ${t} should be greater than 'minDate' ${e}`)}(t.minDate,t.maxDate),t.focusDate=et(t.focusDate,t.minDate,t.maxDate),t.firstDate=et(t.firstDate,t.minDate,t.maxDate),n=t.focusDate),"disabled"in e&&(t.focusVisible=!1),"selectedDate"in e&&0===this._state.months.length&&(n=t.selectedDate),"focusVisible"in e)return t;if("focusDate"in e&&(t.focusDate=et(t.focusDate,t.minDate,t.maxDate),n=t.focusDate,0!==t.months.length&&t.focusDate&&!t.focusDate.before(t.firstDate)&&!t.focusDate.after(t.lastDate)))return t;if("firstDate"in e&&(t.firstDate=et(t.firstDate,t.minDate,t.maxDate),n=t.firstDate),n){const i=function(e,t,n,i,r){const{displayMonths:s,months:o}=n,a=o.splice(0,o.length);return Array.from({length:s},(n,i)=>{const s=Object.assign(e.getNext(t,"m",i),{day:1});if(o[i]=null,!r){const e=a.findIndex(e=>e.firstDate.equals(s));-1!==e&&(o[i]=a.splice(e,1)[0])}return s}).forEach((t,r)=>{null===o[r]&&(o[r]=function(e,t,n,i,r={}){const{dayTemplateData:s,minDate:o,maxDate:a,firstDayOfWeek:c,markDisabled:l,outsideDays:u}=n,d=e.getToday();r.firstDate=null,r.lastDate=null,r.number=t.month,r.year=t.year,r.weeks=r.weeks||[],r.weekdays=r.weekdays||[],t=function(e,t,n){const i=e.getDaysPerWeek(),r=new Ue(t.year,t.month,1),s=e.getWeekday(r)%i;return e.getPrev(r,"d",(i+s-n)%i)}(e,t,c);for(let h=0;he.date),c),n.collapsed="collapsed"===u&&f[0].date.month!==r.number&&f[f.length-1].date.month!==r.number}return r}(e,t,n,i,a.shift()||{}))}),o}(this._calendar,n,t,this._i18n,"dayTemplateData"in e||"firstDayOfWeek"in e||"markDisabled"in e||"minDate"in e||"maxDate"in e||"disabled"in e||"outsideDays"in e);t.months=i,t.firstDate=i[0].firstDate,t.lastDate=i[i.length-1].lastDate,"selectedDate"in e&&!tt(t.selectedDate,t)&&(t.selectedDate=null),"firstDate"in e&&(!t.focusDate||t.focusDate.before(t.firstDate)||t.focusDate.after(t.lastDate))&&(t.focusDate=n);const r=!this._state.firstDate||this._state.firstDate.year!==t.firstDate.year,s=!this._state.firstDate||this._state.firstDate.month!==t.firstDate.month;"select"===t.navigation?(("minDate"in e||"maxDate"in e||0===t.selectBoxes.years.length||r)&&(t.selectBoxes.years=function(e,t,n){if(!e)return[];const i=t?Math.max(t.year,e.year-500):e.year-10,r=(n?Math.min(n.year,e.year+500):e.year+10)-i+1,s=Array(r);for(let o=0;oe===n.month);r=r.slice(e)}if(i&&t.year===i.year){const e=r.findIndex(e=>e===i.month);r=r.slice(0,e+1)}return r}(this._calendar,t.firstDate,t.minDate,t.maxDate))):t.selectBoxes={years:[],months:[]},"arrows"!==t.navigation&&"select"!==t.navigation||!(s||r||"minDate"in e||"maxDate"in e||"disabled"in e)||(t.prevDisabled=t.disabled||function(e,t,n){const i=Object.assign(e.getPrev(t,"m"),{day:1});return null!=n&&(i.year===n.year&&i.month{let e=class{constructor(){this.displayMonths=1,this.firstDayOfWeek=1,this.navigation="select",this.outsideDays="visible",this.showWeekdays=!0,this.showWeekNumbers=!1}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();function at(){return new lt}let ct=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:at,token:e,providedIn:"root"}),e})(),lt=(()=>{let e=class extends ct{fromModel(e){return e&&Ne(e.year)&&Ne(e.month)&&Ne(e.day)?{year:e.year,month:e.month,day:e.day}:null}toModel(e){return e&&Ne(e.year)&&Ne(e.month)&&Ne(e.day)?{year:e.year,month:e.month,day:e.day}:null}};return e.\u0275fac=function(t){return ei(t||e)},e.\u0275prov=i.Ib({token:e,factory:function(t){return e.\u0275fac(t)}}),e})();const ut={provide:s.o,useExisting:Object(i.T)(()=>ht),multi:!0};let dt=(()=>{let e=class{constructor(e){this.templateRef=e}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.L))},e.\u0275dir=i.Hb({type:e,selectors:[["ng-template","ngbDatepickerContent",""]]}),e})(),ht=(()=>{let e=class{constructor(e,t,n,r,s,a,c,l){this._service=e,this._calendar=t,this.i18n=n,this._elementRef=a,this._ngbDateAdapter=c,this._ngZone=l,this._controlValue=null,this._destroyed$=new o.a,this._publicState={},this.navigate=new i.o,this.dateSelect=new i.o,this.select=this.dateSelect,this.onChange=e=>{},this.onTouched=()=>{},["dayTemplate","dayTemplateData","displayMonths","firstDayOfWeek","footerTemplate","markDisabled","minDate","maxDate","navigation","outsideDays","showWeekdays","showWeekNumbers","startDate"].forEach(e=>this[e]=r[e]),e.dateSelect$.pipe(Object(y.a)(this._destroyed$)).subscribe(e=>{this.dateSelect.emit(e)}),e.model$.pipe(Object(y.a)(this._destroyed$)).subscribe(e=>{const t=e.firstDate,n=this.model?this.model.firstDate:null;this._publicState={maxDate:e.maxDate,minDate:e.minDate,firstDate:e.firstDate,lastDate:e.lastDate,focusedDate:e.focusDate,months:e.months.map(e=>e.firstDate)};let i=!1;if(!t.equals(n)&&(this.navigate.emit({current:n?{year:n.year,month:n.month}:null,next:{year:t.year,month:t.month},preventDefault:()=>i=!0}),i&&null!==n))return void this._service.open(n);const r=e.selectedDate,o=e.focusDate,a=this.model?this.model.focusDate:null;this.model=e,Ze(r,this._controlValue)&&(this._controlValue=r,this.onTouched(),this.onChange(this._ngbDateAdapter.toModel(r))),Ze(o,a)&&a&&e.focusVisible&&this.focus(),s.markForCheck()})}get state(){return this._publicState}get calendar(){return this._calendar}focusDate(e){this._service.focus(Ue.from(e))}focusSelect(){this._service.focusSelect()}focus(){this._ngZone.onStable.asObservable().pipe(Object(w.a)(1)).subscribe(()=>{const e=this._elementRef.nativeElement.querySelector('div.ngb-dp-day[tabindex="0"]');e&&e.focus()})}navigateTo(e){this._service.open(Ue.from(e?e.day?e:Object.assign(Object.assign({},e),{day:1}):null))}ngAfterViewInit(){this._ngZone.runOutsideAngular(()=>{const e=Object(c.a)(this._contentEl.nativeElement,"focusin"),t=Object(c.a)(this._contentEl.nativeElement,"focusout"),{nativeElement:n}=this._elementRef;Object(l.a)(e,t).pipe(Object(v.a)(({target:e,relatedTarget:t})=>!(ze(e,"ngb-dp-day")&&ze(t,"ngb-dp-day")&&n.contains(e)&&n.contains(t))),Object(y.a)(this._destroyed$)).subscribe(({type:e})=>this._ngZone.run(()=>this._service.set({focusVisible:"focusin"===e})))})}ngOnDestroy(){this._destroyed$.next()}ngOnInit(){if(void 0===this.model){const e={};["dayTemplateData","displayMonths","markDisabled","firstDayOfWeek","navigation","minDate","maxDate","outsideDays"].forEach(t=>e[t]=this[t]),this._service.set(e),this.navigateTo(this.startDate)}this.dayTemplate||(this.dayTemplate=this._defaultDayTemplate)}ngOnChanges(e){const t={};if(["dayTemplateData","displayMonths","markDisabled","firstDayOfWeek","navigation","minDate","maxDate","outsideDays"].filter(t=>t in e).forEach(e=>t[e]=this[e]),this._service.set(t),"startDate"in e){const{currentValue:t,previousValue:n}=e.startDate;Xe(n,t)&&this.navigateTo(this.startDate)}}onDateSelect(e){this._service.focus(e),this._service.select(e,{emitEvent:!0})}onNavigateDateSelect(e){this._service.open(e)}onNavigateEvent(e){switch(e){case st.PREV:this._service.open(this._calendar.getPrev(this.model.firstDate,"m",1));break;case st.NEXT:this._service.open(this._calendar.getNext(this.model.firstDate,"m",1))}}registerOnChange(e){this.onChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){this._service.set({disabled:e})}writeValue(e){this._controlValue=Ue.from(this._ngbDateAdapter.fromModel(e)),this._service.select(this._controlValue)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(rt),i.Mb(Qe),i.Mb(nt),i.Mb(ot),i.Mb(i.h),i.Mb(i.m),i.Mb(ct),i.Mb(i.A))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-datepicker"]],contentQueries:function(e,t,n){var r;1&e&&i.Ic(n,dt,!0),2&e&&i.zc(r=i.hc())&&(t.contentTemplate=r.first)},viewQuery:function(e,t){var n;1&e&&(i.Jc(L,!0),i.Jc(R,!0)),2&e&&(i.zc(n=i.hc())&&(t._defaultDayTemplate=n.first),i.zc(n=i.hc())&&(t._contentEl=n.first))},inputs:{dayTemplate:"dayTemplate",dayTemplateData:"dayTemplateData",displayMonths:"displayMonths",firstDayOfWeek:"firstDayOfWeek",footerTemplate:"footerTemplate",markDisabled:"markDisabled",maxDate:"maxDate",minDate:"minDate",navigation:"navigation",outsideDays:"outsideDays",showWeekdays:"showWeekdays",showWeekNumbers:"showWeekNumbers",startDate:"startDate"},outputs:{navigate:"navigate",dateSelect:"dateSelect",select:"select"},exportAs:["ngbDatepicker"],features:[i.xb([ut,rt]),i.wb],decls:10,vars:5,consts:[["defaultDayTemplate",""],["defaultContentTemplate",""],[1,"ngb-dp-header"],[3,"date","months","disabled","showSelect","prevDisabled","nextDisabled","selectBoxes","navigate","select",4,"ngIf"],[1,"ngb-dp-content"],["content",""],[3,"ngTemplateOutlet"],["ngbDatepickerDayView","",3,"date","currentMonth","selected","disabled","focused"],["class","ngb-dp-month",4,"ngFor","ngForOf"],[1,"ngb-dp-month"],["class","ngb-dp-month-name",4,"ngIf"],[3,"month"],[1,"ngb-dp-month-name"],[3,"date","months","disabled","showSelect","prevDisabled","nextDisabled","selectBoxes","navigate","select"]],template:function(e,t){if(1&e&&(i.Mc(0,E,1,5,"ng-template",null,0,i.Nc),i.Mc(2,P,1,1,"ng-template",null,1,i.Nc),i.Sb(4,"div",2),i.Mc(5,j,1,7,"ngb-datepicker-navigation",3),i.Rb(),i.Sb(6,"div",4,5),i.Mc(8,N,0,0,"ng-template",6),i.Rb(),i.Mc(9,F,0,0,"ng-template",6)),2&e){const e=i.Ac(3);i.yb(5),i.pc("ngIf","none"!==t.navigation),i.yb(1),i.Eb("ngb-dp-months",!t.contentTemplate),i.yb(2),i.pc("ngTemplateOutlet",(null==t.contentTemplate?null:t.contentTemplate.templateRef)||e),i.yb(1),i.pc("ngTemplateOutlet",t.footerTemplate)}},directives:function(){return[r.r,r.w,Pt,r.q,mt,bt]},styles:["ngb-datepicker{border:1px solid #dfdfdf;border-radius:.25rem;display:inline-block}ngb-datepicker-month{pointer-events:auto}ngb-datepicker.dropdown-menu{padding:0}.ngb-dp-body{z-index:1050}.ngb-dp-header{border-bottom:0;border-radius:.25rem .25rem 0 0;padding-top:.25rem;background-color:#f8f9fa;background-color:var(--light)}.ngb-dp-months{display:-ms-flexbox;display:flex}.ngb-dp-month{pointer-events:none}.ngb-dp-month-name{font-size:larger;height:2rem;line-height:2rem;text-align:center;background-color:#f8f9fa;background-color:var(--light)}.ngb-dp-month+.ngb-dp-month .ngb-dp-month-name,.ngb-dp-month+.ngb-dp-month .ngb-dp-week{padding-left:1rem}.ngb-dp-month:last-child .ngb-dp-week{padding-right:.25rem}.ngb-dp-month:first-child .ngb-dp-week{padding-left:.25rem}.ngb-dp-month .ngb-dp-week:last-child{padding-bottom:.25rem}"],encapsulation:2,changeDetection:0}),e})();var ft=function(e){return e[e.Tab=9]="Tab",e[e.Enter=13]="Enter",e[e.Escape=27]="Escape",e[e.Space=32]="Space",e[e.PageUp=33]="PageUp",e[e.PageDown=34]="PageDown",e[e.End=35]="End",e[e.Home=36]="Home",e[e.ArrowLeft=37]="ArrowLeft",e[e.ArrowUp=38]="ArrowUp",e[e.ArrowRight=39]="ArrowRight",e[e.ArrowDown=40]="ArrowDown",e}({});let pt=(()=>{let e=class{processKey(e,t){const{state:n,calendar:i}=t;switch(e.which){case ft.PageUp:t.focusDate(i.getPrev(n.focusedDate,e.shiftKey?"y":"m",1));break;case ft.PageDown:t.focusDate(i.getNext(n.focusedDate,e.shiftKey?"y":"m",1));break;case ft.End:t.focusDate(e.shiftKey?n.maxDate:n.lastDate);break;case ft.Home:t.focusDate(e.shiftKey?n.minDate:n.firstDate);break;case ft.ArrowLeft:t.focusDate(i.getPrev(n.focusedDate,"d",1));break;case ft.ArrowUp:t.focusDate(i.getPrev(n.focusedDate,"d",i.getDaysPerWeek()));break;case ft.ArrowRight:t.focusDate(i.getNext(n.focusedDate,"d",1));break;case ft.ArrowDown:t.focusDate(i.getNext(n.focusedDate,"d",i.getDaysPerWeek()));break;case ft.Enter:case ft.Space:t.focusSelect();break;default:return}e.preventDefault(),e.stopPropagation()}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})(),mt=(()=>{let e=class{constructor(e,t,n,i){this.i18n=e,this.datepicker=t,this._keyboardService=n,this._service=i}set month(e){this.viewModel=this._service.getMonth(e)}onKeyDown(e){this._keyboardService.processKey(e,this.datepicker)}doSelect(e){e.context.disabled||e.hidden||this.datepicker.onDateSelect(e.date)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(nt),i.Mb(ht),i.Mb(pt),i.Mb(rt))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-datepicker-month"]],hostAttrs:["role","grid"],hostBindings:function(e,t){1&e&&i.gc("keydown",(function(e){return t.onKeyDown(e)}))},inputs:{month:"month"},decls:2,vars:2,consts:[["class","ngb-dp-week ngb-dp-weekdays","role","row",4,"ngIf"],["ngFor","",3,"ngForOf"],["role","row",1,"ngb-dp-week","ngb-dp-weekdays"],["class","ngb-dp-weekday ngb-dp-showweek",4,"ngIf"],["class","ngb-dp-weekday small","role","columnheader",4,"ngFor","ngForOf"],[1,"ngb-dp-weekday","ngb-dp-showweek"],["role","columnheader",1,"ngb-dp-weekday","small"],["class","ngb-dp-week","role","row",4,"ngIf"],["role","row",1,"ngb-dp-week"],["class","ngb-dp-week-number small text-muted",4,"ngIf"],["class","ngb-dp-day","role","gridcell",3,"disabled","tabindex","hidden","ngb-dp-today","click",4,"ngFor","ngForOf"],[1,"ngb-dp-week-number","small","text-muted"],["role","gridcell",1,"ngb-dp-day",3,"tabindex","click"],[3,"ngIf"],[3,"ngTemplateOutlet","ngTemplateOutletContext"]],template:function(e,t){1&e&&(i.Mc(0,$,3,2,"div",0),i.Mc(1,q,1,1,"ng-template",1)),2&e&&(i.pc("ngIf",t.datepicker.showWeekdays),i.yb(1),i.pc("ngForOf",t.viewModel.weeks))},directives:[r.r,r.q,r.w],styles:['ngb-datepicker-month{display:block}.ngb-dp-week-number,.ngb-dp-weekday{line-height:2rem;text-align:center;font-style:italic}.ngb-dp-weekday{color:#5bc0de;color:var(--info)}.ngb-dp-week{border-radius:.25rem;display:-ms-flexbox;display:flex}.ngb-dp-weekdays{border-bottom:1px solid rgba(0,0,0,.125);border-radius:0;background-color:#f8f9fa;background-color:var(--light)}.ngb-dp-day,.ngb-dp-week-number,.ngb-dp-weekday{width:2rem;height:2rem}.ngb-dp-day{cursor:pointer}.ngb-dp-day.disabled,.ngb-dp-day.hidden{cursor:default;pointer-events:none}.ngb-dp-day[tabindex="0"]{z-index:1}'],encapsulation:2}),e})(),bt=(()=>{let e=class{constructor(e){this.i18n=e,this.navigation=st,this.months=[],this.navigate=new i.o,this.select=new i.o}onClickPrev(e){e.currentTarget.focus(),this.navigate.emit(this.navigation.PREV)}onClickNext(e){e.currentTarget.focus(),this.navigate.emit(this.navigation.NEXT)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(nt))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-datepicker-navigation"]],inputs:{months:"months",date:"date",disabled:"disabled",showSelect:"showSelect",prevDisabled:"prevDisabled",nextDisabled:"nextDisabled",selectBoxes:"selectBoxes"},outputs:{navigate:"navigate",select:"select"},decls:10,vars:4,consts:function(){return[[1,"ngb-dp-arrow"],["type","button",1,"btn","btn-link","ngb-dp-arrow-btn",3,"disabled","click",6,"aria-label","title"],["aria-label","Previous month","title","Previous month"],[1,"ngb-dp-navigation-chevron"],["class","ngb-dp-navigation-select",3,"date","disabled","months","years","select",4,"ngIf"],[4,"ngIf"],[1,"ngb-dp-arrow","right"],["aria-label","Next month","title","Next month"],[1,"ngb-dp-navigation-select",3,"date","disabled","months","years","select"],["ngFor","",3,"ngForOf"],["class","ngb-dp-arrow",4,"ngIf"],[1,"ngb-dp-month-name"]]},template:function(e,t){1&e&&(i.Sb(0,"div",0),i.Sb(1,"button",1),i.Yb(2,2),i.gc("click",(function(e){return t.onClickPrev(e)})),i.Nb(3,"span",3),i.Rb(),i.Rb(),i.Mc(4,G,1,4,"ngb-datepicker-navigation-select",4),i.Mc(5,Z,1,1,void 0,5),i.Sb(6,"div",6),i.Sb(7,"button",1),i.Yb(8,7),i.gc("click",(function(e){return t.onClickNext(e)})),i.Nb(9,"span",3),i.Rb(),i.Rb()),2&e&&(i.yb(1),i.pc("disabled",t.prevDisabled),i.yb(3),i.pc("ngIf",t.showSelect),i.yb(1),i.pc("ngIf",!t.showSelect),i.yb(2),i.pc("disabled",t.nextDisabled))},directives:function(){return[r.r,jt,r.q]},styles:["ngb-datepicker-navigation{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.ngb-dp-navigation-chevron{border-style:solid;border-width:.2em .2em 0 0;display:inline-block;width:.75em;height:.75em;margin-left:.25em;margin-right:.15em;-webkit-transform:rotate(-135deg);transform:rotate(-135deg)}.right .ngb-dp-navigation-chevron{-webkit-transform:rotate(45deg);transform:rotate(45deg);margin-left:.15em;margin-right:.25em}.ngb-dp-arrow{display:-ms-flexbox;display:flex;-ms-flex:1 1 auto;flex:1 1 auto;padding-right:0;padding-left:0;margin:0;width:2rem;height:2rem}.ngb-dp-arrow.right{-ms-flex-pack:end;justify-content:flex-end}.ngb-dp-arrow-btn{padding:0 .25rem;margin:0 .5rem;border:none;background-color:transparent;z-index:1}.ngb-dp-arrow-btn:focus{outline-width:1px;outline-style:auto}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){.ngb-dp-arrow-btn:focus{outline-style:solid}}.ngb-dp-month-name{font-size:larger;height:2rem;line-height:2rem;text-align:center}.ngb-dp-navigation-select{display:-ms-flexbox;display:flex;-ms-flex:1 1 9rem;flex:1 1 9rem}"],encapsulation:2,changeDetection:0}),e})();const gt=(e,t)=>!!t&&t.some(t=>t.contains(e)),_t=(e,t)=>!t||null!=function(e,t){return t?void 0===e.closest?null:e.closest(t):null}(e,t),yt=(()=>"undefined"!=typeof navigator&&!!navigator.userAgent&&(/iPad|iPhone|iPod/.test(navigator.userAgent)||/Macintosh/.test(navigator.userAgent)&&navigator.maxTouchPoints&&navigator.maxTouchPoints>2||/Android/.test(navigator.userAgent)))();function vt(e,t,n,i,r,s,o,a){var l;n&&e.runOutsideAngular((l=()=>{const l=Object(c.a)(t,"keydown").pipe(Object(y.a)(r),Object(v.a)(e=>e.which===ft.Escape),Object(S.a)(e=>e.preventDefault())),h=Object(c.a)(t,"mousedown").pipe(Object(g.a)(e=>{const t=e.target;return 2!==e.button&&!gt(t,o)&&("inside"===n?gt(t,s)&&_t(t,a):"outside"===n?!gt(t,s):_t(t,a)||!gt(t,s))}),Object(y.a)(r)),f=Object(c.a)(t,"mouseup").pipe(M(h),Object(v.a)(([e,t])=>t),Object(D.a)(0),Object(y.a)(r));(function(...e){if(1===e.length){if(!Object(u.a)(e[0]))return e[0];e=e[0]}return Object(d.a)(e,void 0).lift(new p)})([l.pipe(Object(g.a)(e=>0)),f.pipe(Object(g.a)(e=>1))]).subscribe(t=>e.run(()=>i(t)))},yt?()=>setTimeout(()=>l(),100):l))}const wt=["a[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","[contenteditable]",'[tabindex]:not([tabindex="-1"])'].join(", ");function St(e){const t=Array.from(e.querySelectorAll(wt)).filter(e=>-1!==e.tabIndex);return[t[0],t[t.length-1]]}const Mt=(e,t,n,i=!1)=>{e.runOutsideAngular(()=>{const e=Object(c.a)(t,"focusin").pipe(Object(y.a)(n),Object(g.a)(e=>e.target));Object(c.a)(t,"keydown").pipe(Object(y.a)(n),Object(v.a)(e=>e.which===ft.Tab),M(e)).subscribe(([e,n])=>{const[i,r]=St(t);n!==i&&n!==t||!e.shiftKey||(r.focus(),e.preventDefault()),n!==r||e.shiftKey||(i.focus(),e.preventDefault())}),i&&Object(c.a)(t,"click").pipe(Object(y.a)(n),M(e),Object(g.a)(e=>e[1])).subscribe(e=>e.focus())})};class xt{getAllStyles(e){return window.getComputedStyle(e)}getStyle(e,t){return this.getAllStyles(e)[t]}isStaticPositioned(e){return"static"===(this.getStyle(e,"position")||"static")}offsetParent(e){let t=e.offsetParent||document.documentElement;for(;t&&t!==document.documentElement&&this.isStaticPositioned(t);)t=t.offsetParent;return t||document.documentElement}position(e,t=!0){let n,i={width:0,height:0,top:0,bottom:0,left:0,right:0};if("fixed"===this.getStyle(e,"position"))n=e.getBoundingClientRect(),n={top:n.top,bottom:n.bottom,left:n.left,right:n.right,height:n.height,width:n.width};else{const t=this.offsetParent(e);n=this.offset(e,!1),t!==document.documentElement&&(i=this.offset(t,!1)),i.top+=t.clientTop,i.left+=t.clientLeft}return n.top-=i.top,n.bottom-=i.top,n.left-=i.left,n.right-=i.left,t&&(n.top=Math.round(n.top),n.bottom=Math.round(n.bottom),n.left=Math.round(n.left),n.right=Math.round(n.right)),n}offset(e,t=!0){const n=e.getBoundingClientRect(),i=window.pageYOffset-document.documentElement.clientTop,r=window.pageXOffset-document.documentElement.clientLeft;let s={height:n.height||e.offsetHeight,width:n.width||e.offsetWidth,top:n.top+i,bottom:n.bottom+i,left:n.left+r,right:n.right+r};return t&&(s.height=Math.round(s.height),s.width=Math.round(s.width),s.top=Math.round(s.top),s.bottom=Math.round(s.bottom),s.left=Math.round(s.left),s.right=Math.round(s.right)),s}positionElements(e,t,n,i){const[r="top",s="center"]=n.split("-"),o=i?this.offset(e,!1):this.position(e,!1),a=this.getAllStyles(t),c=parseFloat(a.marginTop),l=parseFloat(a.marginBottom),u=parseFloat(a.marginLeft),d=parseFloat(a.marginRight);let h=0,f=0;switch(r){case"top":h=o.top-(t.offsetHeight+c+l);break;case"bottom":h=o.top+o.height;break;case"left":f=o.left-(t.offsetWidth+u+d);break;case"right":f=o.left+o.width}switch(s){case"top":h=o.top;break;case"bottom":h=o.top+o.height-t.offsetHeight;break;case"left":f=o.left;break;case"right":f=o.left+o.width-t.offsetWidth;break;case"center":"top"===r||"bottom"===r?f=o.left+o.width/2-t.offsetWidth/2:h=o.top+o.height/2-t.offsetHeight/2}t.style.transform=`translate(${Math.round(f)}px, ${Math.round(h)}px)`;const p=t.getBoundingClientRect(),m=document.documentElement,b=window.innerHeight||m.clientHeight,g=window.innerWidth||m.clientWidth;return p.left>=0&&p.top>=0&&p.right<=g&&p.bottom<=b}}const kt=/\s+/,Dt=new xt;function Tt(e,t,n,i,r){let s=Array.isArray(n)?n:n.split(kt);const o=["top","bottom","left","right","top-left","top-right","bottom-left","bottom-right","left-top","left-bottom","right-top","right-bottom"],a=t.classList,c=e=>{const[t,n]=e.split("-"),i=[];return r&&(i.push(`${r}-${t}`),n&&i.push(`${r}-${t}-${n}`),i.forEach(e=>{a.add(e)})),i};r&&o.forEach(e=>{a.remove(`${r}-${e}`)});let l=s.findIndex(e=>"auto"===e);l>=0&&o.forEach((function(e){null==s.find(t=>-1!==t.search("^"+e))&&s.splice(l++,1,e)}));const u=t.style;u.position="absolute",u.top="0",u.left="0",u["will-change"]="transform";let d=null,h=!1;for(d of s){let n=c(d);if(Dt.positionElements(e,t,d,i)){h=!0;break}r&&n.forEach(e=>{a.remove(e)})}return h||(d=s[0],c(d),Dt.positionElements(e,t,d,i)),d}function Ct(){return new Lt}let Ot=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:Ct,token:e,providedIn:"root"}),e})(),Lt=(()=>{let e=class extends Ot{parse(e){if(null!=e){const t=e.trim().split("-");if(1===t.length&&je(t[0]))return{year:Ae(t[0]),month:null,day:null};if(2===t.length&&je(t[0])&&je(t[1]))return{year:Ae(t[0]),month:Ae(t[1]),day:null};if(3===t.length&&je(t[0])&&je(t[1])&&je(t[2]))return{year:Ae(t[0]),month:Ae(t[1]),day:Ae(t[2])}}return null}format(e){return e?`${e.year}-${je(e.month)?Ye(e.month):""}-${je(e.day)?Ye(e.day):""}`:""}};return e.\u0275fac=function(t){return ti(t||e)},e.\u0275prov=i.Ib({token:e,factory:function(t){return e.\u0275fac(t)}}),e})(),Rt=(()=>{let e=class extends ot{constructor(){super(...arguments),this.autoClose=!0,this.placement=["bottom-left","bottom-right","top-left","top-right"],this.restoreFocus=!0}};return e.\u0275fac=function(t){return ni(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();const Et={provide:s.o,useExisting:Object(i.T)(()=>It),multi:!0},At={provide:s.n,useExisting:Object(i.T)(()=>It),multi:!0};let It=(()=>{let e=class{constructor(e,t,n,r,s,o,a,c,l,u,d){this._parserFormatter=e,this._elRef=t,this._vcRef=n,this._renderer=r,this._cfr=s,this._ngZone=o,this._calendar=a,this._dateAdapter=c,this._document=l,this._changeDetector=u,this._cRef=null,this._disabled=!1,this._elWithFocus=null,this._model=null,this.dateSelect=new i.o,this.navigate=new i.o,this.closed=new i.o,this._onChange=e=>{},this._onTouched=()=>{},this._validatorChange=()=>{},["autoClose","container","positionTarget","placement"].forEach(e=>this[e]=d[e]),this._zoneSubscription=o.onStable.subscribe(()=>this._updatePopupPosition())}get disabled(){return this._disabled}set disabled(e){this._disabled=""===e||e&&"false"!==e,this.isOpen()&&this._cRef.instance.setDisabledState(this._disabled)}registerOnChange(e){this._onChange=e}registerOnTouched(e){this._onTouched=e}registerOnValidatorChange(e){this._validatorChange=e}setDisabledState(e){this.disabled=e}validate(e){const{value:t}=e;if(null!=t){const e=this._fromDateStruct(this._dateAdapter.fromModel(t));if(!e)return{ngbDate:{invalid:t}};if(this.minDate&&e.before(Ue.from(this.minDate)))return{ngbDate:{minDate:{minDate:this.minDate,actual:t}}};if(this.maxDate&&e.after(Ue.from(this.maxDate)))return{ngbDate:{maxDate:{maxDate:this.maxDate,actual:t}}}}return null}writeValue(e){this._model=this._fromDateStruct(this._dateAdapter.fromModel(e)),this._writeModelValue(this._model)}manualDateChange(e,t=!1){const n=e!==this._inputValue;n&&(this._inputValue=e,this._model=this._fromDateStruct(this._parserFormatter.parse(e))),!n&&t||this._onChange(this._model?this._dateAdapter.toModel(this._model):""===e?null:e),t&&this._model&&this._writeModelValue(this._model)}isOpen(){return!!this._cRef}open(){if(!this.isOpen()){const e=this._cfr.resolveComponentFactory(ht);this._cRef=this._vcRef.createComponent(e),this._applyPopupStyling(this._cRef.location.nativeElement),this._applyDatepickerInputs(this._cRef.instance),this._subscribeForDatepickerOutputs(this._cRef.instance),this._cRef.instance.ngOnInit(),this._cRef.instance.writeValue(this._dateAdapter.toModel(this._model)),this._cRef.instance.registerOnChange(e=>{this.writeValue(e),this._onChange(e),this._onTouched()}),this._cRef.changeDetectorRef.detectChanges(),this._cRef.instance.setDisabledState(this.disabled),"body"===this.container&&this._document.querySelector(this.container).appendChild(this._cRef.location.nativeElement),this._elWithFocus=this._document.activeElement,Mt(this._ngZone,this._cRef.location.nativeElement,this.closed,!0),this._cRef.instance.focus(),vt(this._ngZone,this._document,this.autoClose,()=>this.close(),this.closed,[],[this._elRef.nativeElement,this._cRef.location.nativeElement])}}close(){if(this.isOpen()){this._vcRef.remove(this._vcRef.indexOf(this._cRef.hostView)),this._cRef=null,this.closed.emit(),this._changeDetector.markForCheck();let e=this._elWithFocus;Pe(this.restoreFocus)?e=this._document.querySelector(this.restoreFocus):void 0!==this.restoreFocus&&(e=this.restoreFocus),e&&e.focus?e.focus():this._document.body.focus()}}toggle(){this.isOpen()?this.close():this.open()}navigateTo(e){this.isOpen()&&this._cRef.instance.navigateTo(e)}onBlur(){this._onTouched()}onFocus(){this._elWithFocus=this._elRef.nativeElement}ngOnChanges(e){(e.minDate||e.maxDate)&&(this._validatorChange(),this.isOpen()&&(e.minDate&&(this._cRef.instance.minDate=this.minDate),e.maxDate&&(this._cRef.instance.maxDate=this.maxDate),this._cRef.instance.ngOnChanges(e)))}ngOnDestroy(){this.close(),this._zoneSubscription.unsubscribe()}_applyDatepickerInputs(e){["dayTemplate","dayTemplateData","displayMonths","firstDayOfWeek","footerTemplate","markDisabled","minDate","maxDate","navigation","outsideDays","showNavigation","showWeekdays","showWeekNumbers"].forEach(t=>{void 0!==this[t]&&(e[t]=this[t])}),e.startDate=this.startDate||this._model}_applyPopupStyling(e){this._renderer.addClass(e,"dropdown-menu"),this._renderer.addClass(e,"show"),"body"===this.container&&this._renderer.addClass(e,"ngb-dp-body")}_subscribeForDatepickerOutputs(e){e.navigate.subscribe(e=>this.navigate.emit(e)),e.dateSelect.subscribe(e=>{this.dateSelect.emit(e),!0!==this.autoClose&&"inside"!==this.autoClose||this.close()})}_writeModelValue(e){const t=this._parserFormatter.format(e);this._inputValue=t,this._renderer.setProperty(this._elRef.nativeElement,"value",t),this.isOpen()&&(this._cRef.instance.writeValue(this._dateAdapter.toModel(e)),this._onTouched())}_fromDateStruct(e){const t=e?new Ue(e.year,e.month,e.day):null;return this._calendar.isValid(t)?t:null}_updatePopupPosition(){if(!this._cRef)return;let e;if(e=Pe(this.positionTarget)?this._document.querySelector(this.positionTarget):this.positionTarget instanceof HTMLElement?this.positionTarget:this._elRef.nativeElement,this.positionTarget&&!e)throw new Error("ngbDatepicker could not find element declared in [positionTarget] to position against.");Tt(e,this._cRef.location.nativeElement,this.placement,"body"===this.container)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(Ot),i.Mb(i.m),i.Mb(i.P),i.Mb(i.E),i.Mb(i.j),i.Mb(i.A),i.Mb(Qe),i.Mb(ct),i.Mb(r.d),i.Mb(i.h),i.Mb(Rt))},e.\u0275dir=i.Hb({type:e,selectors:[["input","ngbDatepicker",""]],hostVars:1,hostBindings:function(e,t){1&e&&i.gc("input",(function(e){return t.manualDateChange(e.target.value)}))("change",(function(e){return t.manualDateChange(e.target.value,!0)}))("focus",(function(){return t.onFocus()}))("blur",(function(){return t.onBlur()})),2&e&&i.Vb("disabled",t.disabled)},inputs:{disabled:"disabled",autoClose:"autoClose",dayTemplate:"dayTemplate",dayTemplateData:"dayTemplateData",displayMonths:"displayMonths",firstDayOfWeek:"firstDayOfWeek",footerTemplate:"footerTemplate",markDisabled:"markDisabled",minDate:"minDate",maxDate:"maxDate",navigation:"navigation",outsideDays:"outsideDays",placement:"placement",restoreFocus:"restoreFocus",showWeekdays:"showWeekdays",showWeekNumbers:"showWeekNumbers",startDate:"startDate",container:"container",positionTarget:"positionTarget"},outputs:{dateSelect:"dateSelect",navigate:"navigate",closed:"closed"},exportAs:["ngbDatepicker"],features:[i.xb([Et,At,{provide:ot,useExisting:Rt}]),i.wb]}),e})(),Pt=(()=>{let e=class{constructor(e){this.i18n=e}isMuted(){return!this.selected&&(this.date.month!==this.currentMonth||this.disabled)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(nt))},e.\u0275cmp=i.Gb({type:e,selectors:[["","ngbDatepickerDayView",""]],hostAttrs:[1,"btn-light"],hostVars:10,hostBindings:function(e,t){2&e&&i.Eb("bg-primary",t.selected)("text-white",t.selected)("text-muted",t.isMuted())("outside",t.isMuted())("active",t.focused)},inputs:{currentMonth:"currentMonth",date:"date",disabled:"disabled",focused:"focused",selected:"selected"},attrs:X,decls:1,vars:1,template:function(e,t){1&e&&i.Oc(0),2&e&&i.Pc(t.i18n.getDayNumerals(t.date))},styles:["[ngbDatepickerDayView]{text-align:center;width:2rem;height:2rem;line-height:2rem;border-radius:.25rem;background:0 0}[ngbDatepickerDayView].outside{opacity:.5}"],encapsulation:2,changeDetection:0}),e})(),jt=(()=>{let e=class{constructor(e,t){this.i18n=e,this._renderer=t,this.select=new i.o,this._month=-1,this._year=-1}changeMonth(e){this.select.emit(new Ue(this.date.year,Ae(e),1))}changeYear(e){this.select.emit(new Ue(Ae(e),this.date.month,1))}ngAfterViewChecked(){this.date&&(this.date.month!==this._month&&(this._month=this.date.month,this._renderer.setProperty(this.monthSelect.nativeElement,"value",this._month)),this.date.year!==this._year&&(this._year=this.date.year,this._renderer.setProperty(this.yearSelect.nativeElement,"value",this._year)))}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(nt),i.Mb(i.E))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-datepicker-navigation-select"]],viewQuery:function(e,t){var n;1&e&&(i.Jc(ee,!0,i.m),i.Jc(te,!0,i.m)),2&e&&(i.zc(n=i.hc())&&(t.monthSelect=n.first),i.zc(n=i.hc())&&(t.yearSelect=n.first))},inputs:{date:"date",disabled:"disabled",months:"months",years:"years"},outputs:{select:"select"},decls:8,vars:4,consts:function(){return[[1,"custom-select",3,"disabled","change",6,"aria-label","title"],["month",""],["aria-label","Select month","title","Select month"],[3,"value",4,"ngFor","ngForOf"],["year",""],["aria-label","Select year","title","Select year"],[3,"value"]]},template:function(e,t){1&e&&(i.Sb(0,"select",0,1),i.Yb(2,2),i.gc("change",(function(e){return t.changeMonth(e.target.value)})),i.Mc(3,ne,2,3,"option",3),i.Rb(),i.Sb(4,"select",0,4),i.Yb(6,5),i.gc("change",(function(e){return t.changeYear(e.target.value)})),i.Mc(7,ie,2,2,"option",3),i.Rb()),2&e&&(i.pc("disabled",t.disabled),i.yb(3),i.pc("ngForOf",t.months),i.yb(1),i.pc("disabled",t.disabled),i.yb(3),i.pc("ngForOf",t.years))},directives:[r.q,s.u,s.B],styles:["ngb-datepicker-navigation-select>.custom-select{-ms-flex:1 1 auto;flex:1 1 auto;padding:0 .5rem;font-size:.875rem;height:1.85rem}ngb-datepicker-navigation-select>.custom-select:focus{z-index:1}ngb-datepicker-navigation-select>.custom-select::-ms-value{background-color:transparent!important}"],encapsulation:2,changeDetection:0}),e})(),Nt=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c,s.m]]}),e})(),Ft=(()=>{let e=class{constructor(){this.autoClose=!0,this.placement=["bottom-left","bottom-right","top-left","top-right"]}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();var Yt;let zt=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=i.Hb({type:e,selectors:[["",8,"navbar"]]}),e})(),$t=(()=>{let e=class{constructor(e){this.elementRef=e,this._disabled=!1}set disabled(e){this._disabled=""===e||!0===e}get disabled(){return this._disabled}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbDropdownItem",""]],hostAttrs:[1,"dropdown-item"],hostVars:2,hostBindings:function(e,t){2&e&&i.Eb("disabled",t.disabled)},inputs:{disabled:"disabled"}}),e})(),Ht=(()=>{let e=class{constructor(e,t){this.dropdown=e,this.placement="bottom",this.isOpen=!1,this.nativeElement=t.nativeElement}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(Object(i.T)(()=>Bt)),i.Mb(i.m))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbDropdownMenu",""]],contentQueries:function(e,t,n){var r;1&e&&i.Fb(n,$t,!1),2&e&&i.zc(r=i.hc())&&(t.menuItems=r)},hostVars:5,hostBindings:function(e,t){1&e&&i.gc("keydown.ArrowUp",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.ArrowDown",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Home",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.End",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Enter",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Space",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Tab",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Shift.Tab",(function(e){return t.dropdown.onKeyDown(e)})),2&e&&(i.zb("x-placement",t.placement),i.Eb("dropdown-menu",!0)("show",t.dropdown.isOpen()))}}),e})(),Wt=(()=>{let e=class{constructor(e,t){this.dropdown=e,this.nativeElement=t.nativeElement}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(Object(i.T)(()=>Bt)),i.Mb(i.m))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbDropdownAnchor",""]],hostAttrs:[1,"dropdown-toggle"],hostVars:1,hostBindings:function(e,t){2&e&&i.zb("aria-expanded",t.dropdown.isOpen())}}),e})(),Vt=(()=>{let e=Yt=class extends Wt{constructor(e,t){super(e,t)}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(Object(i.T)(()=>Bt)),i.Mb(i.m))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbDropdownToggle",""]],hostAttrs:[1,"dropdown-toggle"],hostVars:1,hostBindings:function(e,t){1&e&&i.gc("click",(function(){return t.dropdown.toggle()}))("keydown.ArrowUp",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.ArrowDown",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Home",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.End",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Tab",(function(e){return t.dropdown.onKeyDown(e)}))("keydown.Shift.Tab",(function(e){return t.dropdown.onKeyDown(e)})),2&e&&i.zb("aria-expanded",t.dropdown.isOpen())},features:[i.xb([{provide:Wt,useExisting:Object(i.T)(()=>Yt)}]),i.vb]}),e})(),Bt=(()=>{let e=class{constructor(e,t,n,r,s,a,c){this._changeDetector=e,this._document=n,this._ngZone=r,this._elementRef=s,this._renderer=a,this._closed$=new o.a,this._bodyContainer=null,this._open=!1,this.openChange=new i.o,this.placement=t.placement,this.container=t.container,this.autoClose=t.autoClose,this.display=c?"static":"dynamic",this._zoneSubscription=r.onStable.subscribe(()=>{this._positionMenu()})}ngAfterContentInit(){this._ngZone.onStable.pipe(Object(w.a)(1)).subscribe(()=>{this._applyPlacementClasses(),this._open&&this._setCloseHandlers()})}ngOnChanges(e){e.container&&this._open&&this._applyContainer(this.container),e.placement&&!e.placement.isFirstChange&&this._applyPlacementClasses()}isOpen(){return this._open}open(){this._open||(this._open=!0,this._applyContainer(this.container),this.openChange.emit(!0),this._setCloseHandlers(),this._anchor&&this._anchor.nativeElement.focus())}_setCloseHandlers(){vt(this._ngZone,this._document,this.autoClose,e=>{this.close(),0===e&&this._anchor.nativeElement.focus()},this._closed$,this._menu?[this._menu.nativeElement]:[],this._anchor?[this._anchor.nativeElement]:[],".dropdown-item,.dropdown-divider")}close(){this._open&&(this._open=!1,this._resetContainer(),this._closed$.next(),this.openChange.emit(!1),this._changeDetector.markForCheck())}toggle(){this.isOpen()?this.close():this.open()}ngOnDestroy(){this._resetContainer(),this._closed$.next(),this._zoneSubscription.unsubscribe()}onKeyDown(e){const t=e.which,n=this._getMenuElements();let i=-1,r=null;const s=this._isEventFromToggle(e);if(!s&&n.length&&n.forEach((t,n)=>{t.contains(e.target)&&(r=t),t===this._document.activeElement&&(i=n)}),t!==ft.Space&&t!==ft.Enter){if(t!==ft.Tab){if(s||r){if(this.open(),n.length){switch(t){case ft.ArrowDown:i=Math.min(i+1,n.length-1);break;case ft.ArrowUp:if(this._isDropup()&&-1===i){i=n.length-1;break}i=Math.max(i-1,0);break;case ft.Home:i=0;break;case ft.End:i=n.length-1}n[i].focus()}e.preventDefault()}}else if(e.target&&this.isOpen()&&this.autoClose){if(this._anchor.nativeElement===e.target)return void("body"!==this.container||e.shiftKey?e.shiftKey&&this.close():(this._renderer.setAttribute(this._menu.nativeElement,"tabindex","0"),this._menu.nativeElement.focus(),this._renderer.removeAttribute(this._menu.nativeElement,"tabindex")));if("body"===this.container){const t=this._menu.nativeElement.querySelectorAll(wt);e.shiftKey&&e.target===t[0]?(this._anchor.nativeElement.focus(),e.preventDefault()):e.shiftKey||e.target!==t[t.length-1]||(this._anchor.nativeElement.focus(),this.close())}else Object(c.a)(e.target,"focusout").pipe(Object(w.a)(1)).subscribe(({relatedTarget:e})=>{this._elementRef.nativeElement.contains(e)||this.close()})}}else!r||!0!==this.autoClose&&"inside"!==this.autoClose||Object(c.a)(r,"click").pipe(Object(w.a)(1)).subscribe(()=>this.close())}_isDropup(){return this._elementRef.nativeElement.classList.contains("dropup")}_isEventFromToggle(e){return this._anchor.nativeElement.contains(e.target)}_getMenuElements(){const e=this._menu;return null==e?[]:e.menuItems.filter(e=>!e.disabled).map(e=>e.elementRef.nativeElement)}_positionMenu(){const e=this._menu;this.isOpen()&&e&&this._applyPlacementClasses("dynamic"===this.display?Tt(this._anchor.nativeElement,this._bodyContainer||this._menu.nativeElement,this.placement,"body"===this.container):this._getFirstPlacement(this.placement))}_getFirstPlacement(e){return Array.isArray(e)?e[0]:e.split(" ")[0]}_resetContainer(){const e=this._renderer;if(this._menu){const t=this._menu.nativeElement;e.appendChild(this._elementRef.nativeElement,t),e.removeStyle(t,"position"),e.removeStyle(t,"transform")}this._bodyContainer&&(e.removeChild(this._document.body,this._bodyContainer),this._bodyContainer=null)}_applyContainer(e=null){if(this._resetContainer(),"body"===e){const e=this._renderer,t=this._menu.nativeElement,n=this._bodyContainer=this._bodyContainer||e.createElement("div");e.setStyle(n,"position","absolute"),e.setStyle(t,"position","static"),e.setStyle(n,"z-index","1050"),e.appendChild(n,t),e.appendChild(this._document.body,n)}}_applyPlacementClasses(e){const t=this._menu;if(t){e||(e=this._getFirstPlacement(this.placement));const n=this._renderer,i=this._elementRef.nativeElement;n.removeClass(i,"dropup"),n.removeClass(i,"dropdown"),t.placement="static"===this.display?null:e;const r=-1!==e.search("^top")?"dropup":"dropdown";n.addClass(i,r);const s=this._bodyContainer;s&&(n.removeClass(s,"dropup"),n.removeClass(s,"dropdown"),n.addClass(s,r))}}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.h),i.Mb(Ft),i.Mb(r.d),i.Mb(i.A),i.Mb(i.m),i.Mb(i.E),i.Mb(zt,8))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbDropdown",""]],contentQueries:function(e,t,n){var r;1&e&&(i.Fb(n,Ht,!0),i.Fb(n,Wt,!0)),2&e&&(i.zc(r=i.hc())&&(t._menu=r.first),i.zc(r=i.hc())&&(t._anchor=r.first))},hostVars:2,hostBindings:function(e,t){2&e&&i.Eb("show",t.isOpen())},inputs:{_open:["open","_open"],placement:"placement",container:"container",autoClose:"autoClose",display:"display"},outputs:{openChange:"openChange"},exportAs:["ngbDropdown"],features:[i.wb]}),e})(),Ut=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)}}),e})(),qt=(()=>{let e=class{constructor(){this.backdrop=!0,this.keyboard=!0}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();class Gt{constructor(e,t,n){this.nodes=e,this.viewRef=t,this.componentRef=n}}class Jt{constructor(e,t,n,i,r,s){this._type=e,this._injector=t,this._viewContainerRef=n,this._renderer=i,this._componentFactoryResolver=r,this._applicationRef=s,this._windowRef=null,this._contentRef=null}open(e,t){return this._windowRef||(this._contentRef=this._getContentRef(e,t),this._windowRef=this._viewContainerRef.createComponent(this._componentFactoryResolver.resolveComponentFactory(this._type),this._viewContainerRef.length,this._injector,this._contentRef.nodes)),this._windowRef}close(){var e;this._windowRef&&(this._viewContainerRef.remove(this._viewContainerRef.indexOf(this._windowRef.hostView)),this._windowRef=null,(null===(e=this._contentRef)||void 0===e?void 0:e.viewRef)&&(this._applicationRef.detachView(this._contentRef.viewRef),this._contentRef.viewRef.destroy(),this._contentRef=null))}_getContentRef(e,t){if(e){if(e instanceof i.L){const n=e.createEmbeddedView(t);return this._applicationRef.attachView(n),new Gt([n.rootNodes],n)}return new Gt([[this._renderer.createText(""+e)]])}return new Gt([])}}const Qt=()=>{};let Kt=(()=>{let e=class{constructor(e){this._document=e}compensate(){const e=this._getWidth();return this._isPresent(e)?this._adjustBody(e):Qt}_adjustBody(e){const t=this._document.body,n=t.style.paddingRight,i=parseFloat(window.getComputedStyle(t)["padding-right"]);return t.style["padding-right"]=i+e+"px",()=>t.style["padding-right"]=n}_isPresent(e){const t=this._document.body.getBoundingClientRect();return window.innerWidth-(t.left+t.right)>=e-.1*e}_getWidth(){const e=this._document.createElement("div");e.className="modal-scrollbar-measure";const t=this._document.body;t.appendChild(e);const n=e.getBoundingClientRect().width-e.clientWidth;return t.removeChild(e),n}};return e.\u0275fac=function(t){return new(t||e)(i.dc(r.d))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(r.d))},token:e,providedIn:"root"}),e})(),Zt=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-modal-backdrop"]],hostAttrs:[2,"z-index","1050"],hostVars:2,hostBindings:function(e,t){2&e&&i.Ab("modal-backdrop fade show"+(t.backdropClass?" "+t.backdropClass:""))},inputs:{backdropClass:"backdropClass"},decls:0,vars:0,template:function(e,t){},encapsulation:2}),e})();class Xt{close(e){}dismiss(e){}}class en{constructor(e,t,n,i){this._windowCmptRef=e,this._contentRef=t,this._backdropCmptRef=n,this._beforeDismiss=i,e.instance.dismissEvent.subscribe(e=>{this.dismiss(e)}),this.result=new Promise((e,t)=>{this._resolve=e,this._reject=t}),this.result.then(null,()=>{})}get componentInstance(){if(this._contentRef&&this._contentRef.componentRef)return this._contentRef.componentRef.instance}close(e){this._windowCmptRef&&(this._resolve(e),this._removeModalElements())}_dismiss(e){this._reject(e),this._removeModalElements()}dismiss(e){if(this._windowCmptRef)if(this._beforeDismiss){const t=this._beforeDismiss();t&&t.then?t.then(t=>{!1!==t&&this._dismiss(e)},()=>{}):!1!==t&&this._dismiss(e)}else this._dismiss(e)}_removeModalElements(){const e=this._windowCmptRef.location.nativeElement;if(e.parentNode.removeChild(e),this._windowCmptRef.destroy(),this._backdropCmptRef){const e=this._backdropCmptRef.location.nativeElement;e.parentNode.removeChild(e),this._backdropCmptRef.destroy()}this._contentRef&&this._contentRef.viewRef&&this._contentRef.viewRef.destroy(),this._windowCmptRef=null,this._backdropCmptRef=null,this._contentRef=null}}var tn=function(e){return e[e.BACKDROP_CLICK=0]="BACKDROP_CLICK",e[e.ESC=1]="ESC",e}({});let nn=(()=>{let e=class{constructor(e,t,n){this._document=e,this._elRef=t,this._zone=n,this._closed$=new o.a,this._elWithFocus=null,this.backdrop=!0,this.keyboard=!0,this.dismissEvent=new i.o}dismiss(e){this.dismissEvent.emit(e)}ngOnInit(){this._elWithFocus=this._document.activeElement}ngAfterViewInit(){const{nativeElement:e}=this._elRef;if(this._zone.runOutsideAngular(()=>{Object(c.a)(e,"keydown").pipe(Object(y.a)(this._closed$),Object(v.a)(e=>e.which===ft.Escape&&this.keyboard)).subscribe(e=>requestAnimationFrame(()=>{e.defaultPrevented||this._zone.run(()=>this.dismiss(tn.ESC))}));let t=!1;Object(c.a)(this._dialogEl.nativeElement,"mousedown").pipe(Object(y.a)(this._closed$),Object(S.a)(()=>t=!1),Object(_.a)(()=>Object(c.a)(e,"mouseup").pipe(Object(y.a)(this._closed$),Object(w.a)(1))),Object(v.a)(({target:t})=>e===t)).subscribe(()=>{t=!0}),Object(c.a)(e,"click").pipe(Object(y.a)(this._closed$)).subscribe(({target:n})=>{!0!==this.backdrop||e!==n||t||this._zone.run(()=>this.dismiss(tn.BACKDROP_CLICK)),t=!1})}),!e.contains(document.activeElement)){const t=e.querySelector("[ngbAutofocus]"),n=St(e)[0];(t||n||e).focus()}}ngOnDestroy(){const e=this._document.body,t=this._elWithFocus;let n;n=t&&t.focus&&e.contains(t)?t:e,this._zone.runOutsideAngular(()=>{setTimeout(()=>n.focus()),this._elWithFocus=null}),this._closed$.next()}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(r.d),i.Mb(i.m),i.Mb(i.A))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-modal-window"]],viewQuery:function(e,t){var n;1&e&&i.Jc(re,!0),2&e&&i.zc(n=i.hc())&&(t._dialogEl=n.first)},hostAttrs:["role","dialog","tabindex","-1"],hostVars:5,hostBindings:function(e,t){2&e&&(i.zb("aria-modal",!0)("aria-labelledby",t.ariaLabelledBy)("aria-describedby",t.ariaDescribedBy),i.Ab("modal fade show d-block"+(t.windowClass?" "+t.windowClass:"")))},inputs:{backdrop:"backdrop",keyboard:"keyboard",ariaLabelledBy:"ariaLabelledBy",ariaDescribedBy:"ariaDescribedBy",centered:"centered",scrollable:"scrollable",size:"size",windowClass:"windowClass"},outputs:{dismissEvent:"dismiss"},ngContentSelectors:O,decls:4,vars:2,consts:[["role","document"],["dialog",""],[1,"modal-content"]],template:function(e,t){1&e&&(i.oc(),i.Sb(0,"div",0,1),i.Sb(2,"div",2),i.nc(3),i.Rb(),i.Rb()),2&e&&i.Ab("modal-dialog"+(t.size?" modal-"+t.size:"")+(t.centered?" modal-dialog-centered":"")+(t.scrollable?" modal-dialog-scrollable":""))},styles:["ngb-modal-window .component-host-scrollable{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;overflow:hidden}"],encapsulation:2}),e})(),rn=(()=>{let e=class{constructor(e,t,n,r,s,a){this._applicationRef=e,this._injector=t,this._document=n,this._scrollBar=r,this._rendererFactory=s,this._ngZone=a,this._activeWindowCmptHasChanged=new o.a,this._ariaHiddenValues=new Map,this._backdropAttributes=["backdropClass"],this._modalRefs=[],this._windowAttributes=["ariaLabelledBy","ariaDescribedBy","backdrop","centered","keyboard","scrollable","size","windowClass"],this._windowCmpts=[],this._activeInstances=new i.o,this._activeWindowCmptHasChanged.subscribe(()=>{if(this._windowCmpts.length){const e=this._windowCmpts[this._windowCmpts.length-1];Mt(this._ngZone,e.location.nativeElement,this._activeWindowCmptHasChanged),this._revertAriaHidden(),this._setAriaHidden(e.location.nativeElement)}})}open(e,t,n,i){const r=i.container instanceof HTMLElement?i.container:Fe(i.container)?this._document.querySelector(i.container):this._document.body,s=this._rendererFactory.createRenderer(null,null),o=this._scrollBar.compensate(),a=()=>{this._modalRefs.length||(s.removeClass(this._document.body,"modal-open"),this._revertAriaHidden())};if(!r)throw new Error(`The specified modal container "${i.container||"body"}" was not found in the DOM.`);const c=new Xt,l=this._getContentRef(e,i.injector||t,n,c,i);let u=!1!==i.backdrop?this._attachBackdrop(e,r):void 0,d=this._attachWindowComponent(e,r,l),h=new en(d,l,u,i.beforeDismiss);return this._registerModalRef(h),this._registerWindowCmpt(d),h.result.then(o,o),h.result.then(a,a),c.close=e=>{h.close(e)},c.dismiss=e=>{h.dismiss(e)},this._applyWindowOptions(d.instance,i),1===this._modalRefs.length&&s.addClass(this._document.body,"modal-open"),u&&u.instance&&this._applyBackdropOptions(u.instance,i),h}get activeInstances(){return this._activeInstances}dismissAll(e){this._modalRefs.forEach(t=>t.dismiss(e))}hasOpenModals(){return this._modalRefs.length>0}_attachBackdrop(e,t){let n=e.resolveComponentFactory(Zt).create(this._injector);return this._applicationRef.attachView(n.hostView),t.appendChild(n.location.nativeElement),n}_attachWindowComponent(e,t,n){let i=e.resolveComponentFactory(nn).create(this._injector,n.nodes);return this._applicationRef.attachView(i.hostView),t.appendChild(i.location.nativeElement),i}_applyWindowOptions(e,t){this._windowAttributes.forEach(n=>{Fe(t[n])&&(e[n]=t[n])})}_applyBackdropOptions(e,t){this._backdropAttributes.forEach(n=>{Fe(t[n])&&(e[n]=t[n])})}_getContentRef(e,t,n,r,s){return n?n instanceof i.L?this._createFromTemplateRef(n,r):Pe(n)?this._createFromString(n):this._createFromComponent(e,t,n,r,s):new Gt([])}_createFromTemplateRef(e,t){const n=e.createEmbeddedView({$implicit:t,close(e){t.close(e)},dismiss(e){t.dismiss(e)}});return this._applicationRef.attachView(n),new Gt([n.rootNodes],n)}_createFromString(e){const t=this._document.createTextNode(""+e);return new Gt([[t]])}_createFromComponent(e,t,n,r,s){const o=e.resolveComponentFactory(n),a=i.s.create({providers:[{provide:Xt,useValue:r}],parent:t}),c=o.create(a),l=c.location.nativeElement;return s.scrollable&&l.classList.add("component-host-scrollable"),this._applicationRef.attachView(c.hostView),new Gt([[l]],c.hostView,c)}_setAriaHidden(e){const t=e.parentElement;t&&e!==this._document.body&&(Array.from(t.children).forEach(t=>{t!==e&&"SCRIPT"!==t.nodeName&&(this._ariaHiddenValues.set(t,t.getAttribute("aria-hidden")),t.setAttribute("aria-hidden","true"))}),this._setAriaHidden(t))}_revertAriaHidden(){this._ariaHiddenValues.forEach((e,t)=>{e?t.setAttribute("aria-hidden",e):t.removeAttribute("aria-hidden")}),this._ariaHiddenValues.clear()}_registerModalRef(e){const t=()=>{const t=this._modalRefs.indexOf(e);t>-1&&(this._modalRefs.splice(t,1),this._activeInstances.emit(this._modalRefs))};this._modalRefs.push(e),this._activeInstances.emit(this._modalRefs),e.result.then(t,t)}_registerWindowCmpt(e){this._windowCmpts.push(e),this._activeWindowCmptHasChanged.next(),e.onDestroy(()=>{const t=this._windowCmpts.indexOf(e);t>-1&&(this._windowCmpts.splice(t,1),this._activeWindowCmptHasChanged.next())})}};return e.\u0275fac=function(t){return new(t||e)(i.dc(i.g),i.dc(i.s),i.dc(r.d),i.dc(Kt),i.dc(i.F),i.dc(i.A))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(i.g),Object(i.dc)(i.p),Object(i.dc)(r.d),Object(i.dc)(Kt),Object(i.dc)(i.F),Object(i.dc)(i.A))},token:e,providedIn:"root"}),e})(),sn=(()=>{let e=class{constructor(e,t,n,i){this._moduleCFR=e,this._injector=t,this._modalStack=n,this._config=i}open(e,t={}){const n=Object.assign({},this._config,t);return this._modalStack.open(this._moduleCFR,this._injector,e,n)}get activeInstances(){return this._modalStack.activeInstances}dismissAll(e){this._modalStack.dismissAll(e)}hasOpenModals(){return this._modalStack.hasOpenModals()}};return e.\u0275fac=function(t){return new(t||e)(i.dc(i.j),i.dc(i.s),i.dc(rn),i.dc(qt))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(i.j),Object(i.dc)(i.p),Object(i.dc)(rn),Object(i.dc)(qt))},token:e,providedIn:"root"}),e})(),on=(()=>{let e=class{constructor(){this.destroyOnHide=!0,this.orientation="horizontal",this.roles="tablist",this.keyboard=!1}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();const an=e=>Fe(e)&&""!==e;let cn=0,ln=(()=>{let e=class{constructor(e){this.templateRef=e}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.L))},e.\u0275dir=i.Hb({type:e,selectors:[["ng-template","ngbNavContent",""]]}),e})(),un=(()=>{let e=class{constructor(e,t){this.elementRef=t,this.disabled=!1,this._nav=e}ngAfterContentChecked(){this.contentTpl=this.contentTpls.first}ngOnInit(){Fe(this.domId)||(this.domId="ngb-nav-"+cn++)}get active(){return this._nav.activeId===this.id}get id(){return an(this._id)?this._id:this.domId}get panelDomId(){return this.domId+"-panel"}isPanelInDom(){return(Fe(this.destroyOnHide)?!this.destroyOnHide:!this._nav.destroyOnHide)||this.active}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(Object(i.T)(()=>dn)),i.Mb(i.m))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbNavItem",""]],contentQueries:function(e,t,n){var r;1&e&&i.Fb(n,ln,!1),2&e&&i.zc(r=i.hc())&&(t.contentTpls=r)},hostVars:2,hostBindings:function(e,t){2&e&&i.Eb("nav-item",!0)},inputs:{disabled:"disabled",domId:"domId",destroyOnHide:"destroyOnHide",_id:["ngbNavItem","_id"]},exportAs:["ngbNavItem"]}),e})(),dn=(()=>{let e=class{constructor(e,t,n,r){this.role=e,this._cd=n,this._document=r,this.activeIdChange=new i.o,this.navChange=new i.o,this.destroyOnHide=t.destroyOnHide,this.orientation=t.orientation,this.roles=t.roles,this.keyboard=t.keyboard}click(e){e.disabled||this._updateActiveId(e.id)}onKeyDown(e){if("tablist"!==this.roles||!this.keyboard)return;const t=e.which,n=this.links.filter(e=>!e.navItem.disabled),{length:i}=n;let r=-1;if(n.forEach((e,t)=>{e.elRef.nativeElement===this._document.activeElement&&(r=t)}),i){switch(t){case ft.ArrowLeft:if("vertical"===this.orientation)return;r=(r-1+i)%i;break;case ft.ArrowRight:if("vertical"===this.orientation)return;r=(r+1)%i;break;case ft.ArrowDown:if("horizontal"===this.orientation)return;r=(r+1)%i;break;case ft.ArrowUp:if("horizontal"===this.orientation)return;r=(r-1+i)%i;break;case ft.Home:r=0;break;case ft.End:r=i-1}"changeWithArrows"===this.keyboard&&this.select(n[r].navItem.id),n[r].elRef.nativeElement.focus(),e.preventDefault()}}select(e){this._updateActiveId(e,!1)}ngAfterContentInit(){if(!Fe(this.activeId)){const e=this.items.first?this.items.first.id:null;an(e)&&(this._updateActiveId(e,!1),this._cd.detectChanges())}}_updateActiveId(e,t=!0){if(this.activeId!==e){let n=!1;t&&this.navChange.emit({activeId:this.activeId,nextId:e,preventDefault:()=>{n=!0}}),n||(this.activeId=e,this.activeIdChange.emit(e))}}};return e.\u0275fac=function(t){return new(t||e)(i.ec("role"),i.Mb(on),i.Mb(i.h),i.Mb(r.d))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbNav",""]],contentQueries:function(e,t,n){var r;1&e&&(i.Fb(n,un,!1),i.Fb(n,hn,!0)),2&e&&(i.zc(r=i.hc())&&(t.items=r),i.zc(r=i.hc())&&(t.links=r))},hostVars:6,hostBindings:function(e,t){1&e&&i.gc("keydown.arrowLeft",(function(e){return t.onKeyDown(e)}))("keydown.arrowRight",(function(e){return t.onKeyDown(e)}))("keydown.arrowDown",(function(e){return t.onKeyDown(e)}))("keydown.arrowUp",(function(e){return t.onKeyDown(e)}))("keydown.Home",(function(e){return t.onKeyDown(e)}))("keydown.End",(function(e){return t.onKeyDown(e)})),2&e&&(i.zb("aria-orientation","vertical"===t.orientation&&"tablist"===t.roles?"vertical":void 0)("role",t.role?t.role:t.roles?"tablist":void 0),i.Eb("nav",!0)("flex-column","vertical"===t.orientation))},inputs:{destroyOnHide:"destroyOnHide",orientation:"orientation",roles:"roles",keyboard:"keyboard",activeId:"activeId"},outputs:{activeIdChange:"activeIdChange",navChange:"navChange"},exportAs:["ngbNav"]}),e})(),hn=(()=>{let e=class{constructor(e,t,n,i){this.role=e,this.navItem=t,this.nav=n,this.elRef=i}hasNavItemClass(){return this.navItem.elementRef.nativeElement.nodeType===Node.COMMENT_NODE}};return e.\u0275fac=function(t){return new(t||e)(i.ec("role"),i.Mb(un),i.Mb(dn),i.Mb(i.m))},e.\u0275dir=i.Hb({type:e,selectors:[["a","ngbNavLink",""]],hostAttrs:["href",""],hostVars:14,hostBindings:function(e,t){1&e&&i.gc("click",(function(e){return t.nav.click(t.navItem),e.preventDefault()})),2&e&&(i.Vb("id",t.navItem.domId),i.zb("role",t.role?t.role:t.nav.roles?"tab":void 0)("tabindex",t.navItem.disabled?-1:void 0)("aria-controls",t.navItem.isPanelInDom()?t.navItem.panelDomId:null)("aria-selected",t.navItem.active)("aria-disabled",t.navItem.disabled),i.Eb("nav-link",!0)("nav-item",t.hasNavItemClass())("active",t.navItem.active)("disabled",t.navItem.disabled))}}),e})(),fn=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["","ngbNavOutlet",""]],hostVars:2,hostBindings:function(e,t){2&e&&i.Eb("tab-content",!0)},inputs:{paneRole:"paneRole",nav:["ngbNavOutlet","nav"]},attrs:se,decls:1,vars:1,consts:[["ngFor","",3,"ngForOf"],["class","tab-pane",3,"id","active",4,"ngIf"],[1,"tab-pane",3,"id"],[3,"ngTemplateOutlet","ngTemplateOutletContext"]],template:function(e,t){1&e&&i.Mc(0,le,1,1,"ng-template",0),2&e&&i.pc("ngForOf",t.nav.items)},directives:[r.q,r.r,r.w],encapsulation:2}),e})(),pn=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c]]}),e})();class mn{constructor(e,t){this.open=e,this.close=t,t||(this.close=e)}isManual(){return"manual"===this.open||"manual"===this.close}}const bn={hover:["mouseenter","mouseleave"],focus:["focusin","focusout"]},gn=e=>e>0?Object(D.a)(e):e=>e;function _n(e,t,n,i,r,s,o=0,a=0){const c=function(e,t=bn){const n=(e||"").trim();if(0===n.length)return[];const i=n.split(/\s+/).map(e=>e.split(":")).map(e=>{let n=t[e[0]]||e;return new mn(n[0],n[1])}),r=i.filter(e=>e.isManual());if(r.length>1)throw"Triggers parse error: only one manual trigger is allowed";if(1===r.length&&i.length>1)throw"Triggers parse error: manual trigger can't be mixed with other triggers";return i}(n);if(1===c.length&&c[0].isManual())return()=>{};const u=function(e,t,n,i){return new b.a(r=>{const s=[],o=()=>r.next(!0),a=()=>r.next(!1),c=()=>r.next(!i());return n.forEach(n=>{n.open===n.close?s.push(e.listen(t,n.open,c)):s.push(e.listen(t,n.open,o),e.listen(t,n.close,a))}),()=>{s.forEach(e=>e())}})}(e,t,c,i).pipe(function(e,t,n){return i=>{let r=null;const s=i.pipe(Object(g.a)(e=>({open:e})),Object(v.a)(e=>{const t=n();return t===e.open||r&&r.open!==t?(r&&r.open!==e.open&&(r=null),!1):(r=e,!0)}),Object(T.a)()),o=s.pipe(Object(v.a)(e=>e.open),gn(e)),a=s.pipe(Object(v.a)(e=>!e.open),gn(t));return Object(l.a)(o,a).pipe(Object(v.a)(e=>e===r&&(r=null,e.open!==n())),Object(g.a)(e=>e.open))}}(o,a,i)).subscribe(e=>e?r():s());return()=>u.unsubscribe()}let yn=(()=>{let e=class{constructor(){this.autoClose=!0,this.placement="auto",this.triggers="click",this.disablePopover=!1,this.openDelay=0,this.closeDelay=0}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})(),vn=0,wn=(()=>{let e=class{isTitleTemplate(){return this.title instanceof i.L}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-popover-window"]],hostAttrs:["role","tooltip"],hostVars:3,hostBindings:function(e,t){2&e&&(i.Vb("id",t.id),i.Ab("popover"+(t.popoverClass?" "+t.popoverClass:"")))},inputs:{title:"title",id:"id",popoverClass:"popoverClass",context:"context"},ngContentSelectors:O,decls:4,vars:1,consts:[[1,"arrow"],["class","popover-header",4,"ngIf"],[1,"popover-body"],[1,"popover-header"],["simpleTitle",""],[3,"ngTemplateOutlet","ngTemplateOutletContext"]],template:function(e,t){1&e&&(i.oc(),i.Nb(0,"div",0),i.Mc(1,he,4,2,"h3",1),i.Sb(2,"div",2),i.nc(3),i.Rb()),2&e&&(i.yb(1),i.pc("ngIf",null!=t.title))},directives:[r.r,r.w],styles:["ngb-popover-window.bs-popover-bottom>.arrow,ngb-popover-window.bs-popover-top>.arrow{left:50%;margin-left:-.5rem}ngb-popover-window.bs-popover-bottom-left>.arrow,ngb-popover-window.bs-popover-top-left>.arrow{left:2em}ngb-popover-window.bs-popover-bottom-right>.arrow,ngb-popover-window.bs-popover-top-right>.arrow{left:auto;right:2em}ngb-popover-window.bs-popover-left>.arrow,ngb-popover-window.bs-popover-right>.arrow{top:50%;margin-top:-.5rem}ngb-popover-window.bs-popover-left-top>.arrow,ngb-popover-window.bs-popover-right-top>.arrow{top:.7em}ngb-popover-window.bs-popover-left-bottom>.arrow,ngb-popover-window.bs-popover-right-bottom>.arrow{top:auto;bottom:.7em}"],encapsulation:2,changeDetection:0}),e})(),Sn=(()=>{let e=class{constructor(e,t,n,r,s,o,a,c,l,u){this._elementRef=e,this._renderer=t,this._ngZone=a,this._document=c,this._changeDetector=l,this.shown=new i.o,this.hidden=new i.o,this._ngbPopoverWindowId="ngb-popover-"+vn++,this._windowRef=null,this.autoClose=o.autoClose,this.placement=o.placement,this.triggers=o.triggers,this.container=o.container,this.disablePopover=o.disablePopover,this.popoverClass=o.popoverClass,this.openDelay=o.openDelay,this.closeDelay=o.closeDelay,this._popupService=new Jt(wn,n,s,t,r,u),this._zoneSubscription=a.onStable.subscribe(()=>{this._windowRef&&Tt(this._elementRef.nativeElement,this._windowRef.location.nativeElement,this.placement,"body"===this.container,"bs-popover")})}_isDisabled(){return!!this.disablePopover||!this.ngbPopover&&!this.popoverTitle}open(e){this._windowRef||this._isDisabled()||(this._windowRef=this._popupService.open(this.ngbPopover,e),this._windowRef.instance.title=this.popoverTitle,this._windowRef.instance.context=e,this._windowRef.instance.popoverClass=this.popoverClass,this._windowRef.instance.id=this._ngbPopoverWindowId,this._renderer.setAttribute(this._elementRef.nativeElement,"aria-describedby",this._ngbPopoverWindowId),"body"===this.container&&this._document.querySelector(this.container).appendChild(this._windowRef.location.nativeElement),this._windowRef.changeDetectorRef.detectChanges(),this._windowRef.changeDetectorRef.markForCheck(),vt(this._ngZone,this._document,this.autoClose,()=>this.close(),this.hidden,[this._windowRef.location.nativeElement]),this.shown.emit())}close(){this._windowRef&&(this._renderer.removeAttribute(this._elementRef.nativeElement,"aria-describedby"),this._popupService.close(),this._windowRef=null,this.hidden.emit(),this._changeDetector.markForCheck())}toggle(){this._windowRef?this.close():this.open()}isOpen(){return null!=this._windowRef}ngOnInit(){this._unregisterListenersFn=_n(this._renderer,this._elementRef.nativeElement,this.triggers,this.isOpen.bind(this),this.open.bind(this),this.close.bind(this),+this.openDelay,+this.closeDelay)}ngOnChanges({ngbPopover:e,popoverTitle:t,disablePopover:n,popoverClass:i}){i&&this.isOpen()&&(this._windowRef.instance.popoverClass=i.currentValue),(e||t||n)&&this._isDisabled()&&this.close()}ngOnDestroy(){this.close(),this._unregisterListenersFn&&this._unregisterListenersFn(),this._zoneSubscription.unsubscribe()}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m),i.Mb(i.E),i.Mb(i.s),i.Mb(i.j),i.Mb(i.P),i.Mb(yn),i.Mb(i.A),i.Mb(r.d),i.Mb(i.h),i.Mb(i.g))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbPopover",""]],inputs:{autoClose:"autoClose",placement:"placement",triggers:"triggers",container:"container",disablePopover:"disablePopover",popoverClass:"popoverClass",openDelay:"openDelay",closeDelay:"closeDelay",ngbPopover:"ngbPopover",popoverTitle:"popoverTitle"},outputs:{shown:"shown",hidden:"hidden"},exportAs:["ngbPopover"],features:[i.wb]}),e})(),Mn=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c]]}),e})(),xn=(()=>{let e=class{constructor(){this.max=100,this.animated=!1,this.striped=!1,this.showValue=!1}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})(),kn=(()=>{let e=class{constructor(e){this.value=0,this.max=e.max,this.animated=e.animated,this.striped=e.striped,this.textType=e.textType,this.type=e.type,this.showValue=e.showValue,this.height=e.height}set max(e){this._max=!je(e)||e<=0?100:e}get max(){return this._max}getValue(){return function(e,t,n=0){return Math.max(Math.min(e,t),n)}(this.value,this.max)}getPercentValue(){return 100*this.getValue()/this.max}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(xn))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-progressbar"]],inputs:{value:"value",max:"max",animated:"animated",striped:"striped",textType:"textType",type:"type",showValue:"showValue",height:"height"},ngContentSelectors:O,decls:4,vars:13,consts:function(){return[[1,"progress"],["role","progressbar","aria-valuemin","0"],[4,"ngIf"],"" + "\ufffd0\ufffd" + ""]},template:function(e,t){1&e&&(i.oc(),i.Sb(0,"div",0),i.Sb(1,"div",1),i.Mc(2,fe,3,3,"span",2),i.nc(3),i.Rb(),i.Rb()),2&e&&(i.Kc("height",t.height),i.yb(1),i.Db("progress-bar",t.type?" bg-"+t.type:"","",t.textType?" text-"+t.textType:"","\n ",t.animated?" progress-bar-animated":"","",t.striped?" progress-bar-striped":"",""),i.Kc("width",t.getPercentValue(),"%"),i.zb("aria-valuenow",t.getValue())("aria-valuemax",t.max),i.yb(1),i.pc("ngIf",t.showValue))},directives:[r.r],pipes:[r.y],encapsulation:2,changeDetection:0}),e})(),Dn=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c]]}),e})();class Tn{constructor(e,t,n){this.hour=Ae(e),this.minute=Ae(t),this.second=Ae(n)}changeHour(e=1){this.updateHour((isNaN(this.hour)?0:this.hour)+e)}updateHour(e){this.hour=je(e)?(e<0?24+e:e)%24:NaN}changeMinute(e=1){this.updateMinute((isNaN(this.minute)?0:this.minute)+e)}updateMinute(e){je(e)?(this.minute=e%60<0?60+e%60:e%60,this.changeHour(Math.floor(e/60))):this.minute=NaN}changeSecond(e=1){this.updateSecond((isNaN(this.second)?0:this.second)+e)}updateSecond(e){je(e)?(this.second=e<0?60+e%60:e%60,this.changeMinute(Math.floor(e/60))):this.second=NaN}isValid(e=!0){return je(this.hour)&&je(this.minute)&&(!e||je(this.second))}toString(){return`${this.hour||0}:${this.minute||0}:${this.second||0}`}}let Cn=(()=>{let e=class{constructor(){this.meridian=!1,this.spinners=!0,this.seconds=!1,this.hourStep=1,this.minuteStep=1,this.secondStep=1,this.disabled=!1,this.readonlyInputs=!1,this.size="medium"}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();function On(){return new Rn}let Ln=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:On,token:e,providedIn:"root"}),e})(),Rn=(()=>{let e=class extends Ln{fromModel(e){return e&&Ne(e.hour)&&Ne(e.minute)?{hour:e.hour,minute:e.minute,second:Ne(e.second)?e.second:null}:null}toModel(e){return e&&Ne(e.hour)&&Ne(e.minute)?{hour:e.hour,minute:e.minute,second:Ne(e.second)?e.second:null}:null}};return e.\u0275fac=function(t){return ii(t||e)},e.\u0275prov=i.Ib({token:e,factory:function(t){return e.\u0275fac(t)}}),e})(),En=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return e=Object(i.dc)(i.v),new An(e);var e},token:e,providedIn:"root"}),e})(),An=(()=>{let e=class extends En{constructor(e){super(),this._periods=Object(r.G)(e,r.g.Standalone,r.B.Narrow)}getMorningPeriod(){return this._periods[0]}getAfternoonPeriod(){return this._periods[1]}};return e.\u0275fac=function(t){return new(t||e)(i.dc(i.v))},e.\u0275prov=i.Ib({token:e,factory:function(t){return e.\u0275fac(t)}}),e})();const In=/[^0-9]/g,Pn={provide:s.o,useExisting:Object(i.T)(()=>jn),multi:!0};let jn=(()=>{let e=class{constructor(e,t,n,i){this._config=e,this._ngbTimeAdapter=t,this._cd=n,this.i18n=i,this.onChange=e=>{},this.onTouched=()=>{},this.meridian=e.meridian,this.spinners=e.spinners,this.seconds=e.seconds,this.hourStep=e.hourStep,this.minuteStep=e.minuteStep,this.secondStep=e.secondStep,this.disabled=e.disabled,this.readonlyInputs=e.readonlyInputs,this.size=e.size}set hourStep(e){this._hourStep=Ne(e)?e:this._config.hourStep}get hourStep(){return this._hourStep}set minuteStep(e){this._minuteStep=Ne(e)?e:this._config.minuteStep}get minuteStep(){return this._minuteStep}set secondStep(e){this._secondStep=Ne(e)?e:this._config.secondStep}get secondStep(){return this._secondStep}writeValue(e){const t=this._ngbTimeAdapter.fromModel(e);this.model=t?new Tn(t.hour,t.minute,t.second):new Tn,this.seconds||t&&je(t.second)||(this.model.second=0),this._cd.markForCheck()}registerOnChange(e){this.onChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){this.disabled=e}changeHour(e){this.model.changeHour(e),this.propagateModelChange()}changeMinute(e){this.model.changeMinute(e),this.propagateModelChange()}changeSecond(e){this.model.changeSecond(e),this.propagateModelChange()}updateHour(e){const t=this.model.hour>=12,n=Ae(e);this.model.updateHour(this.meridian&&(t&&n<12||!t&&12===n)?n+12:n),this.propagateModelChange()}updateMinute(e){this.model.updateMinute(Ae(e)),this.propagateModelChange()}updateSecond(e){this.model.updateSecond(Ae(e)),this.propagateModelChange()}toggleMeridian(){this.meridian&&this.changeHour(12)}formatInput(e){e.value=e.value.replace(In,"")}formatHour(e){return je(e)?Ye(this.meridian?e%12==0?12:e%12:e%24):Ye(NaN)}formatMinSec(e){return Ye(je(e)?e:NaN)}get isSmallSize(){return"small"===this.size}get isLargeSize(){return"large"===this.size}ngOnChanges(e){e.seconds&&!this.seconds&&this.model&&!je(this.model.second)&&(this.model.second=0,this.propagateModelChange(!1))}propagateModelChange(e=!0){e&&this.onTouched(),this.model.isValid(this.seconds)?this.onChange(this._ngbTimeAdapter.toModel({hour:this.model.hour,minute:this.model.minute,second:this.model.second})):this.onChange(this._ngbTimeAdapter.toModel(null))}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(Cn),i.Mb(Ln),i.Mb(i.h),i.Mb(En))},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-timepicker"]],inputs:{meridian:"meridian",spinners:"spinners",seconds:"seconds",hourStep:"hourStep",minuteStep:"minuteStep",secondStep:"secondStep",readonlyInputs:"readonlyInputs",size:"size"},features:[i.xb([Pn]),i.wb],decls:18,vars:25,consts:function(){return[[3,"disabled"],[1,"ngb-tp"],[1,"ngb-tp-input-container","ngb-tp-hour"],["tabindex","-1","type","button","class","btn btn-link",3,"btn-sm","btn-lg","disabled","click",4,"ngIf"],["type","text","maxlength","2","inputmode","numeric",1,"ngb-tp-input","form-control",3,"value","readOnly","disabled","change","input","keydown.ArrowUp","keydown.ArrowDown",6,"placeholder","aria-label"],["placeholder","HH","aria-label","Hours"],[1,"ngb-tp-spacer"],[1,"ngb-tp-input-container","ngb-tp-minute"],["placeholder","MM","aria-label","Minutes"],["class","ngb-tp-spacer",4,"ngIf"],["class","ngb-tp-input-container ngb-tp-second",4,"ngIf"],["class","ngb-tp-meridian",4,"ngIf"],["tabindex","-1","type","button",1,"btn","btn-link",3,"disabled","click"],[1,"chevron","ngb-tp-chevron"],[1,"sr-only"],"Increment hours",[1,"chevron","ngb-tp-chevron","bottom"],"Decrement hours","Increment minutes","Decrement minutes",[1,"ngb-tp-input-container","ngb-tp-second"],["placeholder","SS","aria-label","Seconds"],"Increment seconds","Decrement seconds",[1,"ngb-tp-meridian"],["type","button",1,"btn","btn-outline-primary",3,"disabled","click"],[4,"ngIf","ngIfElse"],["am",""],"" + "\ufffd0\ufffd" + "","" + "\ufffd0\ufffd" + ""]},template:function(e,t){1&e&&(i.Sb(0,"fieldset",0),i.Sb(1,"div",1),i.Sb(2,"div",2),i.Mc(3,pe,4,7,"button",3),i.Sb(4,"input",4),i.Yb(5,5),i.gc("change",(function(e){return t.updateHour(e.target.value)}))("input",(function(e){return t.formatInput(e.target)}))("keydown.ArrowUp",(function(e){return t.changeHour(t.hourStep),e.preventDefault()}))("keydown.ArrowDown",(function(e){return t.changeHour(-t.hourStep),e.preventDefault()})),i.Rb(),i.Mc(6,me,4,7,"button",3),i.Rb(),i.Sb(7,"div",6),i.Oc(8,":"),i.Rb(),i.Sb(9,"div",7),i.Mc(10,be,4,7,"button",3),i.Sb(11,"input",4),i.Yb(12,8),i.gc("change",(function(e){return t.updateMinute(e.target.value)}))("input",(function(e){return t.formatInput(e.target)}))("keydown.ArrowUp",(function(e){return t.changeMinute(t.minuteStep),e.preventDefault()}))("keydown.ArrowDown",(function(e){return t.changeMinute(-t.minuteStep),e.preventDefault()})),i.Rb(),i.Mc(13,ge,4,7,"button",3),i.Rb(),i.Mc(14,_e,2,0,"div",9),i.Mc(15,we,5,9,"div",10),i.Mc(16,Se,1,0,"div",9),i.Mc(17,ke,5,9,"div",11),i.Rb(),i.Rb()),2&e&&(i.Eb("disabled",t.disabled),i.pc("disabled",t.disabled),i.yb(3),i.pc("ngIf",t.spinners),i.yb(1),i.Eb("form-control-sm",t.isSmallSize)("form-control-lg",t.isLargeSize),i.pc("value",t.formatHour(null==t.model?null:t.model.hour))("readOnly",t.readonlyInputs)("disabled",t.disabled),i.yb(2),i.pc("ngIf",t.spinners),i.yb(4),i.pc("ngIf",t.spinners),i.yb(1),i.Eb("form-control-sm",t.isSmallSize)("form-control-lg",t.isLargeSize),i.pc("value",t.formatMinSec(null==t.model?null:t.model.minute))("readOnly",t.readonlyInputs)("disabled",t.disabled),i.yb(2),i.pc("ngIf",t.spinners),i.yb(1),i.pc("ngIf",t.seconds),i.yb(1),i.pc("ngIf",t.seconds),i.yb(1),i.pc("ngIf",t.meridian),i.yb(1),i.pc("ngIf",t.meridian))},directives:[r.r],styles:['ngb-timepicker{font-size:1rem}.ngb-tp{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.ngb-tp-input-container{width:4em}.ngb-tp-chevron::before{border-style:solid;border-width:.29em .29em 0 0;content:"";display:inline-block;height:.69em;left:.05em;position:relative;top:.15em;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);vertical-align:middle;width:.69em}.ngb-tp-chevron.bottom:before{top:-.3em;-webkit-transform:rotate(135deg);transform:rotate(135deg)}.ngb-tp-input{text-align:center}.ngb-tp-hour,.ngb-tp-meridian,.ngb-tp-minute,.ngb-tp-second{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.ngb-tp-spacer{width:1em;text-align:center}'],encapsulation:2}),e})(),Nn=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c]]}),e})(),Fn=(()=>{let e=class{constructor(){this.autoClose=!0,this.placement="auto",this.triggers="hover focus",this.disableTooltip=!1,this.openDelay=0,this.closeDelay=0}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})(),Yn=0,zn=(()=>{let e=class{};return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-tooltip-window"]],hostAttrs:["role","tooltip"],hostVars:3,hostBindings:function(e,t){2&e&&(i.Vb("id",t.id),i.Ab("tooltip show"+(t.tooltipClass?" "+t.tooltipClass:"")))},inputs:{id:"id",tooltipClass:"tooltipClass"},ngContentSelectors:O,decls:3,vars:0,consts:[[1,"arrow"],[1,"tooltip-inner"]],template:function(e,t){1&e&&(i.oc(),i.Nb(0,"div",0),i.Sb(1,"div",1),i.nc(2),i.Rb())},styles:["ngb-tooltip-window.bs-tooltip-bottom .arrow,ngb-tooltip-window.bs-tooltip-top .arrow{left:calc(50% - .4rem)}ngb-tooltip-window.bs-tooltip-bottom-left .arrow,ngb-tooltip-window.bs-tooltip-top-left .arrow{left:1em}ngb-tooltip-window.bs-tooltip-bottom-right .arrow,ngb-tooltip-window.bs-tooltip-top-right .arrow{left:auto;right:.8rem}ngb-tooltip-window.bs-tooltip-left .arrow,ngb-tooltip-window.bs-tooltip-right .arrow{top:calc(50% - .4rem)}ngb-tooltip-window.bs-tooltip-left-top .arrow,ngb-tooltip-window.bs-tooltip-right-top .arrow{top:.4rem}ngb-tooltip-window.bs-tooltip-left-bottom .arrow,ngb-tooltip-window.bs-tooltip-right-bottom .arrow{top:auto;bottom:.4rem}"],encapsulation:2,changeDetection:0}),e})(),$n=(()=>{let e=class{constructor(e,t,n,r,s,o,a,c,l,u){this._elementRef=e,this._renderer=t,this._ngZone=a,this._document=c,this._changeDetector=l,this.shown=new i.o,this.hidden=new i.o,this._ngbTooltipWindowId="ngb-tooltip-"+Yn++,this._windowRef=null,this.autoClose=o.autoClose,this.placement=o.placement,this.triggers=o.triggers,this.container=o.container,this.disableTooltip=o.disableTooltip,this.tooltipClass=o.tooltipClass,this.openDelay=o.openDelay,this.closeDelay=o.closeDelay,this._popupService=new Jt(zn,n,s,t,r,u),this._zoneSubscription=a.onStable.subscribe(()=>{this._windowRef&&Tt(this._elementRef.nativeElement,this._windowRef.location.nativeElement,this.placement,"body"===this.container,"bs-tooltip")})}set ngbTooltip(e){this._ngbTooltip=e,!e&&this._windowRef&&this.close()}get ngbTooltip(){return this._ngbTooltip}open(e){this._windowRef||!this._ngbTooltip||this.disableTooltip||(this._windowRef=this._popupService.open(this._ngbTooltip,e),this._windowRef.instance.tooltipClass=this.tooltipClass,this._windowRef.instance.id=this._ngbTooltipWindowId,this._renderer.setAttribute(this._elementRef.nativeElement,"aria-describedby",this._ngbTooltipWindowId),"body"===this.container&&this._document.querySelector(this.container).appendChild(this._windowRef.location.nativeElement),this._windowRef.changeDetectorRef.detectChanges(),this._windowRef.changeDetectorRef.markForCheck(),vt(this._ngZone,this._document,this.autoClose,()=>this.close(),this.hidden,[this._windowRef.location.nativeElement]),this.shown.emit())}close(){null!=this._windowRef&&(this._renderer.removeAttribute(this._elementRef.nativeElement,"aria-describedby"),this._popupService.close(),this._windowRef=null,this.hidden.emit(),this._changeDetector.markForCheck())}toggle(){this._windowRef?this.close():this.open()}isOpen(){return null!=this._windowRef}ngOnInit(){this._unregisterListenersFn=_n(this._renderer,this._elementRef.nativeElement,this.triggers,this.isOpen.bind(this),this.open.bind(this),this.close.bind(this),+this.openDelay,+this.closeDelay)}ngOnChanges({tooltipClass:e}){e&&this.isOpen()&&(this._windowRef.instance.tooltipClass=e.currentValue)}ngOnDestroy(){this.close(),this._unregisterListenersFn&&this._unregisterListenersFn(),this._zoneSubscription.unsubscribe()}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m),i.Mb(i.E),i.Mb(i.s),i.Mb(i.j),i.Mb(i.P),i.Mb(Fn),i.Mb(i.A),i.Mb(r.d),i.Mb(i.h),i.Mb(i.g))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngbTooltip",""]],inputs:{autoClose:"autoClose",placement:"placement",triggers:"triggers",container:"container",disableTooltip:"disableTooltip",tooltipClass:"tooltipClass",openDelay:"openDelay",closeDelay:"closeDelay",ngbTooltip:"ngbTooltip"},outputs:{shown:"shown",hidden:"hidden"},exportAs:["ngbTooltip"],features:[i.wb]}),e})(),Hn=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)}}),e})(),Wn=(()=>{let e=class{constructor(){this.highlightClass="ngb-highlight"}ngOnChanges(e){const t=Ie(this.result),n=(Array.isArray(this.term)?this.term:[this.term]).map(e=>Ie(e).replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")).filter(e=>e);this.parts=n.length?t.split(new RegExp(`(${n.join("|")})`,"gmi")):[t]}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-highlight"]],inputs:{highlightClass:"highlightClass",result:"result",term:"term"},features:[i.wb],decls:1,vars:1,consts:[["ngFor","",3,"ngForOf"],[3,"class",4,"ngIf","ngIfElse"],["even",""]],template:function(e,t){1&e&&i.Mc(0,Ce,3,2,"ng-template",0),2&e&&i.pc("ngForOf",t.parts)},directives:[r.q,r.r],styles:[".ngb-highlight{font-weight:700}"],encapsulation:2,changeDetection:0}),e})(),Vn=(()=>{let e=class{constructor(){this.activeIdx=0,this.focusFirst=!0,this.formatter=Ie,this.selectEvent=new i.o,this.activeChangeEvent=new i.o}hasActive(){return this.activeIdx>-1&&this.activeIdx=0?this.id+"-"+this.activeIdx:void 0)}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["ngb-typeahead-window"]],hostAttrs:["role","listbox",1,"dropdown-menu","show"],hostVars:1,hostBindings:function(e,t){1&e&&i.gc("mousedown",(function(e){return e.preventDefault()})),2&e&&i.Vb("id",t.id)},inputs:{focusFirst:"focusFirst",formatter:"formatter",id:"id",results:"results",term:"term",resultTemplate:"resultTemplate"},outputs:{selectEvent:"select",activeChangeEvent:"activeChange"},exportAs:["ngbTypeaheadWindow"],decls:3,vars:1,consts:[["rt",""],["ngFor","",3,"ngForOf"],[3,"result","term"],["type","button","role","option",1,"dropdown-item",3,"id","mouseenter","click"],[3,"ngTemplateOutlet","ngTemplateOutletContext"]],template:function(e,t){1&e&&(i.Mc(0,Oe,1,2,"ng-template",null,0,i.Nc),i.Mc(2,Ee,2,9,"ng-template",1)),2&e&&(i.yb(2),i.pc("ngForOf",t.results))},directives:[r.q,Wn,r.w],encapsulation:2}),e})();const Bn=new i.r("live announcer delay",{providedIn:"root",factory:function(){return 100}});function Un(e,t=!1){let n=e.body.querySelector("#ngb-live");return null==n&&t&&(n=e.createElement("div"),n.setAttribute("id","ngb-live"),n.setAttribute("aria-live","polite"),n.setAttribute("aria-atomic","true"),n.classList.add("sr-only"),e.body.appendChild(n)),n}let qn=(()=>{let e=class{constructor(e,t){this._document=e,this._delay=t}ngOnDestroy(){const e=Un(this._document);e&&e.parentElement.removeChild(e)}say(e){const t=Un(this._document,!0),n=this._delay;if(null!=t){t.textContent="";const i=()=>t.textContent=e;null===n?i():setTimeout(i,n)}}};return e.\u0275fac=function(t){return new(t||e)(i.dc(r.d),i.dc(Bn))},e.\u0275prov=Object(i.Ib)({factory:function(){return new e(Object(i.dc)(r.d),Object(i.dc)(Bn))},token:e,providedIn:"root"}),e})(),Gn=(()=>{let e=class{constructor(){this.editable=!0,this.focusFirst=!0,this.showHint=!1,this.placement=["bottom-left","bottom-right","top-left","top-right"]}};return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:function(){return new e},token:e,providedIn:"root"}),e})();const Jn={provide:s.o,useExisting:Object(i.T)(()=>Kn),multi:!0};let Qn=0,Kn=(()=>{let e=class{constructor(e,t,n,r,s,l,u,d,h,f,p,m){this._elementRef=e,this._renderer=n,this._live=d,this._document=h,this._ngZone=f,this._changeDetector=p,this._subscription=null,this._closed$=new o.a,this._inputValueBackup=null,this._windowRef=null,this.autocomplete="off",this.placement="bottom-left",this.selectItem=new i.o,this.activeDescendant=null,this.popupId="ngb-typeahead-"+Qn++,this._onTouched=()=>{},this._onChange=e=>{},this.container=l.container,this.editable=l.editable,this.focusFirst=l.focusFirst,this.showHint=l.showHint,this.placement=l.placement,this._valueChanges=Object(c.a)(e.nativeElement,"input").pipe(Object(g.a)(e=>e.target.value)),this._resubscribeTypeahead=new a.a(null),this._popupService=new Jt(Vn,r,t,n,s,m),this._zoneSubscription=u.onStable.subscribe(()=>{this.isPopupOpen()&&Tt(this._elementRef.nativeElement,this._windowRef.location.nativeElement,this.placement,"body"===this.container)})}ngOnInit(){const e=this._valueChanges.pipe(Object(S.a)(e=>{this._inputValueBackup=this.showHint?e:null,this._onChange(this.editable?e:void 0)})).pipe(this.ngbTypeahead),t=this._resubscribeTypeahead.pipe(Object(_.a)(()=>e));this._subscription=this._subscribeToUserInput(t)}ngOnDestroy(){this._closePopup(),this._unsubscribeFromUserInput(),this._zoneSubscription.unsubscribe()}registerOnChange(e){this._onChange=e}registerOnTouched(e){this._onTouched=e}writeValue(e){this._writeInputValue(this._formatItemForInput(e)),this.showHint&&(this._inputValueBackup=e)}setDisabledState(e){this._renderer.setProperty(this._elementRef.nativeElement,"disabled",e)}dismissPopup(){this.isPopupOpen()&&(this._resubscribeTypeahead.next(null),this._closePopup(),this.showHint&&null!==this._inputValueBackup&&this._writeInputValue(this._inputValueBackup),this._changeDetector.markForCheck())}isPopupOpen(){return null!=this._windowRef}handleBlur(){this._resubscribeTypeahead.next(null),this._onTouched()}handleKeyDown(e){if(this.isPopupOpen())switch(e.which){case ft.ArrowDown:e.preventDefault(),this._windowRef.instance.next(),this._showHint();break;case ft.ArrowUp:e.preventDefault(),this._windowRef.instance.prev(),this._showHint();break;case ft.Enter:case ft.Tab:const t=this._windowRef.instance.getActive();Fe(t)&&(e.preventDefault(),e.stopPropagation(),this._selectResult(t)),this._closePopup()}}_openPopup(){this.isPopupOpen()||(this._inputValueBackup=this._elementRef.nativeElement.value,this._windowRef=this._popupService.open(),this._windowRef.instance.id=this.popupId,this._windowRef.instance.selectEvent.subscribe(e=>this._selectResultClosePopup(e)),this._windowRef.instance.activeChangeEvent.subscribe(e=>this.activeDescendant=e),"body"===this.container&&this._document.querySelector(this.container).appendChild(this._windowRef.location.nativeElement),this._changeDetector.markForCheck(),vt(this._ngZone,this._document,"outside",()=>this.dismissPopup(),this._closed$,[this._elementRef.nativeElement,this._windowRef.location.nativeElement]))}_closePopup(){this._closed$.next(),this._popupService.close(),this._windowRef=null,this.activeDescendant=null}_selectResult(e){let t=!1;this.selectItem.emit({item:e,preventDefault:()=>{t=!0}}),this._resubscribeTypeahead.next(null),t||(this.writeValue(e),this._onChange(e))}_selectResultClosePopup(e){this._selectResult(e),this._closePopup()}_showHint(){var e;if(this.showHint&&(null===(e=this._windowRef)||void 0===e?void 0:e.instance.hasActive())&&null!=this._inputValueBackup){const e=this._inputValueBackup.toLowerCase(),t=this._formatItemForInput(this._windowRef.instance.getActive());e===t.substr(0,this._inputValueBackup.length).toLowerCase()?(this._writeInputValue(this._inputValueBackup+t.substr(this._inputValueBackup.length)),this._elementRef.nativeElement.setSelectionRange.apply(this._elementRef.nativeElement,[this._inputValueBackup.length,t.length])):this._writeInputValue(t)}}_formatItemForInput(e){return null!=e&&this.inputFormatter?this.inputFormatter(e):Ie(e)}_writeInputValue(e){this._renderer.setProperty(this._elementRef.nativeElement,"value",Ie(e))}_subscribeToUserInput(e){return e.subscribe(e=>{e&&0!==e.length?(this._openPopup(),this._windowRef.instance.focusFirst=this.focusFirst,this._windowRef.instance.results=e,this._windowRef.instance.term=this._elementRef.nativeElement.value,this.resultFormatter&&(this._windowRef.instance.formatter=this.resultFormatter),this.resultTemplate&&(this._windowRef.instance.resultTemplate=this.resultTemplate),this._windowRef.instance.resetActive(),this._windowRef.changeDetectorRef.detectChanges(),this._showHint()):this._closePopup();const t=e?e.length:0;this._live.say(0===t?"No results available":`${t} result${1===t?"":"s"} available`)})}_unsubscribeFromUserInput(){this._subscription&&this._subscription.unsubscribe(),this._subscription=null}};return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m),i.Mb(i.P),i.Mb(i.E),i.Mb(i.s),i.Mb(i.j),i.Mb(Gn),i.Mb(i.A),i.Mb(qn),i.Mb(r.d),i.Mb(i.A),i.Mb(i.h),i.Mb(i.g))},e.\u0275dir=i.Hb({type:e,selectors:[["input","ngbTypeahead",""]],hostAttrs:["autocapitalize","off","autocorrect","off","role","combobox","aria-multiline","false"],hostVars:7,hostBindings:function(e,t){1&e&&i.gc("blur",(function(){return t.handleBlur()}))("keydown",(function(e){return t.handleKeyDown(e)})),2&e&&(i.Vb("autocomplete",t.autocomplete),i.zb("aria-autocomplete",t.showHint?"both":"list")("aria-activedescendant",t.activeDescendant)("aria-owns",t.isPopupOpen()?t.popupId:null)("aria-expanded",t.isPopupOpen()),i.Eb("open",t.isPopupOpen()))},inputs:{autocomplete:"autocomplete",placement:"placement",container:"container",editable:"editable",focusFirst:"focusFirst",showHint:"showHint",inputFormatter:"inputFormatter",ngbTypeahead:"ngbTypeahead",resultFormatter:"resultFormatter",resultTemplate:"resultTemplate"},outputs:{selectItem:"selectItem"},exportAs:["ngbTypeahead"],features:[i.xb([Jn])]}),e})(),Zn=(()=>{let e=class{};return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},imports:[[r.c]]}),e})();const Xn=i.Ub(Ke),ei=i.Ub(lt),ti=i.Ub(Lt),ni=i.Ub(Rt),ii=i.Ub(Rn)},"G1/K":function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");let o=(()=>{class e{transform(e,t){return""===e?r.a.defaultTo(t,"n/a"):e}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=s.Lb({name:"notAvailable",type:e,pure:!0}),e})()},G1I9:function(e,t,n){"use strict";n.d(t,"b",(function(){return s})),n.d(t,"a",(function(){return o}));var i=n("oxzT"),r=n("mtw6");class s{constructor(e=r.a.info,t,n,i,s="Ceph"){this.type=e,this.title=t,this.message=n,this.options=i,this.application=s,this.isFinishedTask=!1,this.classes={Ceph:"ceph-icon",Prometheus:"prometheus-icon"},this.applicationClass=this.classes[this.application]}}class o extends s{constructor(e=new s){super(e.type,e.title,e.message,e.options,e.application),this.config=e,this.textClasses=["text-danger","text-info","text-success"],this.iconClasses=[i.a.warning,i.a.info,i.a.check],this.borderClasses=["border-danger","border-info","border-success"],delete this.config,this.timestamp=(new Date).toJSON(),this.iconClass=this.iconClasses[this.type],this.textClass=this.textClasses[this.type],this.borderClass=this.borderClasses[this.type],this.isFinishedTask=e.isFinishedTask}}},G4mU:function(e,t,n){"use strict";var i=n("lkxz");t.a=function(e,t){var n=t?Object(i.a)(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}},"G6Q+":function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("SVse"),r=n("iInd"),s=n("PCNd"),o=n("8Y7J");let a=(()=>{class e{}return e.\u0275mod=o.Kb({type:e}),e.\u0275inj=o.Jb({factory:function(t){return new(t||e)},imports:[[i.c,s.a,r.i]]}),e})()},GS7A:function(e,t,n){"use strict";n.d(t,"a",(function(){return s})),n.d(t,"b",(function(){return i})),n.d(t,"c",(function(){return r})),n.d(t,"d",(function(){return f})),n.d(t,"e",(function(){return a})),n.d(t,"f",(function(){return c})),n.d(t,"g",(function(){return u})),n.d(t,"h",(function(){return l})),n.d(t,"i",(function(){return d})),n.d(t,"j",(function(){return o})),n.d(t,"k",(function(){return p})),n.d(t,"l",(function(){return m}));class i{}class r{}const s="*";function o(e,t){return{type:7,name:e,definitions:t,options:{}}}function a(e,t=null){return{type:4,styles:t,timings:e}}function c(e,t=null){return{type:2,steps:e,options:t}}function l(e){return{type:6,styles:e,offset:null}}function u(e,t,n){return{type:0,name:e,styles:t,options:n}}function d(e,t,n=null){return{type:1,expr:e,animation:t,options:n}}function h(e){Promise.resolve(null).then(e)}class f{constructor(e=0,t=0){this._onDoneFns=[],this._onStartFns=[],this._onDestroyFns=[],this._started=!1,this._destroyed=!1,this._finished=!1,this.parentPlayer=null,this.totalTime=e+t}_onFinish(){this._finished||(this._finished=!0,this._onDoneFns.forEach(e=>e()),this._onDoneFns=[])}onStart(e){this._onStartFns.push(e)}onDone(e){this._onDoneFns.push(e)}onDestroy(e){this._onDestroyFns.push(e)}hasStarted(){return this._started}init(){}play(){this.hasStarted()||(this._onStart(),this.triggerMicrotask()),this._started=!0}triggerMicrotask(){h(()=>this._onFinish())}_onStart(){this._onStartFns.forEach(e=>e()),this._onStartFns=[]}pause(){}restart(){}finish(){this._onFinish()}destroy(){this._destroyed||(this._destroyed=!0,this.hasStarted()||this._onStart(),this.finish(),this._onDestroyFns.forEach(e=>e()),this._onDestroyFns=[])}reset(){}setPosition(e){}getPosition(){return 0}triggerCallback(e){const t="start"==e?this._onStartFns:this._onDoneFns;t.forEach(e=>e()),t.length=0}}class p{constructor(e){this._onDoneFns=[],this._onStartFns=[],this._finished=!1,this._started=!1,this._destroyed=!1,this._onDestroyFns=[],this.parentPlayer=null,this.totalTime=0,this.players=e;let t=0,n=0,i=0;const r=this.players.length;0==r?h(()=>this._onFinish()):this.players.forEach(e=>{e.onDone(()=>{++t==r&&this._onFinish()}),e.onDestroy(()=>{++n==r&&this._onDestroy()}),e.onStart(()=>{++i==r&&this._onStart()})}),this.totalTime=this.players.reduce((e,t)=>Math.max(e,t.totalTime),0)}_onFinish(){this._finished||(this._finished=!0,this._onDoneFns.forEach(e=>e()),this._onDoneFns=[])}init(){this.players.forEach(e=>e.init())}onStart(e){this._onStartFns.push(e)}_onStart(){this.hasStarted()||(this._started=!0,this._onStartFns.forEach(e=>e()),this._onStartFns=[])}onDone(e){this._onDoneFns.push(e)}onDestroy(e){this._onDestroyFns.push(e)}hasStarted(){return this._started}play(){this.parentPlayer||this.init(),this._onStart(),this.players.forEach(e=>e.play())}pause(){this.players.forEach(e=>e.pause())}restart(){this.players.forEach(e=>e.restart())}finish(){this._onFinish(),this.players.forEach(e=>e.finish())}destroy(){this._onDestroy()}_onDestroy(){this._destroyed||(this._destroyed=!0,this._onFinish(),this.players.forEach(e=>e.destroy()),this._onDestroyFns.forEach(e=>e()),this._onDestroyFns=[])}reset(){this.players.forEach(e=>e.reset()),this._destroyed=!1,this._finished=!1,this._started=!1}setPosition(e){const t=e*this.totalTime;this.players.forEach(e=>{const n=e.totalTime?Math.min(1,t/e.totalTime):1;e.setPosition(n)})}getPosition(){let e=0;return this.players.forEach(t=>{const n=t.getPosition();e=Math.min(n,e)}),e}beforeDestroy(){this.players.forEach(e=>{e.beforeDestroy&&e.beforeDestroy()})}triggerCallback(e){const t="start"==e?this._onStartFns:this._onDoneFns;t.forEach(e=>e()),t.length=0}}const m="!"},GarU:function(e,t){e.exports=function(e,t,n){if(!(e instanceof t))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return e}},GgAd:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("8Y7J"),r=n("G0yt"),s=n("SVse"),o=n("Fgil"),a=n("o4+5");function c(e,t){if(1&e&&(i.Sb(0,"table"),i.Sb(1,"tr"),i.Sb(2,"td",4),i.Oc(3,"Used:\xa0"),i.Rb(),i.Sb(4,"td",5),i.Sb(5,"strong"),i.Oc(6),i.jc(7,"dimlessBinary"),i.jc(8,"dimless"),i.Rb(),i.Rb(),i.Rb(),i.Sb(9,"tr"),i.Sb(10,"td",4),i.Oc(11,"Free:\xa0"),i.Rb(),i.Sb(12,"td",6),i.Sb(13,"strong"),i.Oc(14),i.jc(15,"dimlessBinary"),i.jc(16,"dimless"),i.Rb(),i.Rb(),i.Rb(),i.Rb()),2&e){const e=i.ic();i.yb(6),i.Qc(" ",e.isBinary?i.kc(7,2,e.used):i.kc(8,4,e.used),""),i.yb(8),i.Pc(e.isBinary?i.kc(15,6,e.total-e.used):i.kc(16,8,e.total-e.used))}}let l=(()=>{class e{constructor(){this.isBinary=!0,this.decimals=0}ngOnChanges(){this.usedPercentage=this.total>0?this.used/this.total*100:0,this.freePercentage=100-this.usedPercentage}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["cd-usage-bar"]],inputs:{total:"total",used:"used",isBinary:"isBinary",decimals:"decimals"},features:[i.wb],decls:8,vars:9,consts:[["usageTooltipTpl",""],["data-placement","left",1,"progress",3,"ngbTooltip"],["role","progressbar",1,"progress-bar","bg-info"],["role","progressbar",1,"progress-bar","bg-freespace"],[1,"text-left"],[1,"text-right"],[1,"'text-right"]],template:function(e,t){if(1&e&&(i.Mc(0,c,17,10,"ng-template",null,0,i.Nc),i.Sb(2,"div",1),i.Sb(3,"div",2),i.Sb(4,"span"),i.Oc(5),i.jc(6,"number"),i.Rb(),i.Rb(),i.Nb(7,"div",3),i.Rb()),2&e){const e=i.Ac(1);i.yb(2),i.pc("ngbTooltip",e),i.yb(1),i.Kc("width",t.usedPercentage+"%"),i.yb(2),i.Qc("",i.lc(6,6,t.usedPercentage,"1.0-"+t.decimals),"%"),i.yb(2),i.Kc("width",t.freePercentage+"%")}},directives:[r.D],pipes:[s.f,o.a,a.a],styles:[".bg-info[_ngcontent-%COMP%]{background-color:#2b99a8!important}.bg-freespace[_ngcontent-%COMP%]{background-color:#ced4da!important}.progress[_ngcontent-%COMP%]{height:20px;margin-bottom:0;position:relative}.progress[_ngcontent-%COMP%] div.progress-bar[_ngcontent-%COMP%]{position:static}.progress[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{color:#000;display:block;font-weight:400;position:absolute;width:100%}"]}),e})()},GyhO:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("LRne"),r=n("0EUg");function s(...e){return Object(r.a)()(Object(i.a)(...e))}},H8ED:function(e,t,n){!function(e){"use strict";function t(e,t,n){return"m"===n?t?"\u0445\u0432\u0456\u043b\u0456\u043d\u0430":"\u0445\u0432\u0456\u043b\u0456\u043d\u0443":"h"===n?t?"\u0433\u0430\u0434\u0437\u0456\u043d\u0430":"\u0433\u0430\u0434\u0437\u0456\u043d\u0443":e+" "+(i=+e,r={ss:t?"\u0441\u0435\u043a\u0443\u043d\u0434\u0430_\u0441\u0435\u043a\u0443\u043d\u0434\u044b_\u0441\u0435\u043a\u0443\u043d\u0434":"\u0441\u0435\u043a\u0443\u043d\u0434\u0443_\u0441\u0435\u043a\u0443\u043d\u0434\u044b_\u0441\u0435\u043a\u0443\u043d\u0434",mm:t?"\u0445\u0432\u0456\u043b\u0456\u043d\u0430_\u0445\u0432\u0456\u043b\u0456\u043d\u044b_\u0445\u0432\u0456\u043b\u0456\u043d":"\u0445\u0432\u0456\u043b\u0456\u043d\u0443_\u0445\u0432\u0456\u043b\u0456\u043d\u044b_\u0445\u0432\u0456\u043b\u0456\u043d",hh:t?"\u0433\u0430\u0434\u0437\u0456\u043d\u0430_\u0433\u0430\u0434\u0437\u0456\u043d\u044b_\u0433\u0430\u0434\u0437\u0456\u043d":"\u0433\u0430\u0434\u0437\u0456\u043d\u0443_\u0433\u0430\u0434\u0437\u0456\u043d\u044b_\u0433\u0430\u0434\u0437\u0456\u043d",dd:"\u0434\u0437\u0435\u043d\u044c_\u0434\u043d\u0456_\u0434\u0437\u0451\u043d",MM:"\u043c\u0435\u0441\u044f\u0446_\u043c\u0435\u0441\u044f\u0446\u044b_\u043c\u0435\u0441\u044f\u0446\u0430\u045e",yy:"\u0433\u043e\u0434_\u0433\u0430\u0434\u044b_\u0433\u0430\u0434\u043e\u045e"}[n].split("_"),i%10==1&&i%100!=11?r[0]:i%10>=2&&i%10<=4&&(i%100<10||i%100>=20)?r[1]:r[2]);var i,r}e.defineLocale("be",{months:{format:"\u0441\u0442\u0443\u0434\u0437\u0435\u043d\u044f_\u043b\u044e\u0442\u0430\u0433\u0430_\u0441\u0430\u043a\u0430\u0432\u0456\u043a\u0430_\u043a\u0440\u0430\u0441\u0430\u0432\u0456\u043a\u0430_\u0442\u0440\u0430\u045e\u043d\u044f_\u0447\u044d\u0440\u0432\u0435\u043d\u044f_\u043b\u0456\u043f\u0435\u043d\u044f_\u0436\u043d\u0456\u045e\u043d\u044f_\u0432\u0435\u0440\u0430\u0441\u043d\u044f_\u043a\u0430\u0441\u0442\u0440\u044b\u0447\u043d\u0456\u043a\u0430_\u043b\u0456\u0441\u0442\u0430\u043f\u0430\u0434\u0430_\u0441\u043d\u0435\u0436\u043d\u044f".split("_"),standalone:"\u0441\u0442\u0443\u0434\u0437\u0435\u043d\u044c_\u043b\u044e\u0442\u044b_\u0441\u0430\u043a\u0430\u0432\u0456\u043a_\u043a\u0440\u0430\u0441\u0430\u0432\u0456\u043a_\u0442\u0440\u0430\u0432\u0435\u043d\u044c_\u0447\u044d\u0440\u0432\u0435\u043d\u044c_\u043b\u0456\u043f\u0435\u043d\u044c_\u0436\u043d\u0456\u0432\u0435\u043d\u044c_\u0432\u0435\u0440\u0430\u0441\u0435\u043d\u044c_\u043a\u0430\u0441\u0442\u0440\u044b\u0447\u043d\u0456\u043a_\u043b\u0456\u0441\u0442\u0430\u043f\u0430\u0434_\u0441\u043d\u0435\u0436\u0430\u043d\u044c".split("_")},monthsShort:"\u0441\u0442\u0443\u0434_\u043b\u044e\u0442_\u0441\u0430\u043a_\u043a\u0440\u0430\u0441_\u0442\u0440\u0430\u0432_\u0447\u044d\u0440\u0432_\u043b\u0456\u043f_\u0436\u043d\u0456\u0432_\u0432\u0435\u0440_\u043a\u0430\u0441\u0442_\u043b\u0456\u0441\u0442_\u0441\u043d\u0435\u0436".split("_"),weekdays:{format:"\u043d\u044f\u0434\u0437\u0435\u043b\u044e_\u043f\u0430\u043d\u044f\u0434\u0437\u0435\u043b\u0430\u043a_\u0430\u045e\u0442\u043e\u0440\u0430\u043a_\u0441\u0435\u0440\u0430\u0434\u0443_\u0447\u0430\u0446\u0432\u0435\u0440_\u043f\u044f\u0442\u043d\u0456\u0446\u0443_\u0441\u0443\u0431\u043e\u0442\u0443".split("_"),standalone:"\u043d\u044f\u0434\u0437\u0435\u043b\u044f_\u043f\u0430\u043d\u044f\u0434\u0437\u0435\u043b\u0430\u043a_\u0430\u045e\u0442\u043e\u0440\u0430\u043a_\u0441\u0435\u0440\u0430\u0434\u0430_\u0447\u0430\u0446\u0432\u0435\u0440_\u043f\u044f\u0442\u043d\u0456\u0446\u0430_\u0441\u0443\u0431\u043e\u0442\u0430".split("_"),isFormat:/\[ ?[\u0423\u0443\u045e] ?(?:\u043c\u0456\u043d\u0443\u043b\u0443\u044e|\u043d\u0430\u0441\u0442\u0443\u043f\u043d\u0443\u044e)? ?\] ?dddd/},weekdaysShort:"\u043d\u0434_\u043f\u043d_\u0430\u0442_\u0441\u0440_\u0447\u0446_\u043f\u0442_\u0441\u0431".split("_"),weekdaysMin:"\u043d\u0434_\u043f\u043d_\u0430\u0442_\u0441\u0440_\u0447\u0446_\u043f\u0442_\u0441\u0431".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY \u0433.",LLL:"D MMMM YYYY \u0433., HH:mm",LLLL:"dddd, D MMMM YYYY \u0433., HH:mm"},calendar:{sameDay:"[\u0421\u0451\u043d\u043d\u044f \u045e] LT",nextDay:"[\u0417\u0430\u045e\u0442\u0440\u0430 \u045e] LT",lastDay:"[\u0423\u0447\u043e\u0440\u0430 \u045e] LT",nextWeek:function(){return"[\u0423] dddd [\u045e] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[\u0423 \u043c\u0456\u043d\u0443\u043b\u0443\u044e] dddd [\u045e] LT";case 1:case 2:case 4:return"[\u0423 \u043c\u0456\u043d\u0443\u043b\u044b] dddd [\u045e] LT"}},sameElse:"L"},relativeTime:{future:"\u043f\u0440\u0430\u0437 %s",past:"%s \u0442\u0430\u043c\u0443",s:"\u043d\u0435\u043a\u0430\u043b\u044c\u043a\u0456 \u0441\u0435\u043a\u0443\u043d\u0434",m:t,mm:t,h:t,hh:t,d:"\u0434\u0437\u0435\u043d\u044c",dd:t,M:"\u043c\u0435\u0441\u044f\u0446",MM:t,y:"\u0433\u043e\u0434",yy:t},meridiemParse:/\u043d\u043e\u0447\u044b|\u0440\u0430\u043d\u0456\u0446\u044b|\u0434\u043d\u044f|\u0432\u0435\u0447\u0430\u0440\u0430/,isPM:function(e){return/^(\u0434\u043d\u044f|\u0432\u0435\u0447\u0430\u0440\u0430)$/.test(e)},meridiem:function(e,t,n){return e<4?"\u043d\u043e\u0447\u044b":e<12?"\u0440\u0430\u043d\u0456\u0446\u044b":e<17?"\u0434\u043d\u044f":"\u0432\u0435\u0447\u0430\u0440\u0430"},dayOfMonthOrdinalParse:/\d{1,2}-(\u0456|\u044b|\u0433\u0430)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":case"w":case"W":return e%10!=2&&e%10!=3||e%100==12||e%100==13?e+"-\u044b":e+"-\u0456";case"D":return e+"-\u0433\u0430";default:return e}},week:{dow:1,doy:7}})}(n("wd/R"))},HAuM:function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},HDdC:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("7o/Q"),r=n("2QA8"),s=n("gRHU"),o=n("kJWO"),a=n("mCNh"),c=n("2fFW");let l=(()=>{class e{constructor(e){this._isScalar=!1,e&&(this._subscribe=e)}lift(t){const n=new e;return n.source=this,n.operator=t,n}subscribe(e,t,n){const{operator:o}=this,a=function(e,t,n){if(e){if(e instanceof i.a)return e;if(e[r.a])return e[r.a]()}return e||t||n?new i.a(e,t,n):new i.a(s.a)}(e,t,n);if(a.add(o?o.call(a,this.source):this.source||c.a.useDeprecatedSynchronousErrorHandling&&!a.syncErrorThrowable?this._subscribe(a):this._trySubscribe(a)),c.a.useDeprecatedSynchronousErrorHandling&&a.syncErrorThrowable&&(a.syncErrorThrowable=!1,a.syncErrorThrown))throw a.syncErrorValue;return a}_trySubscribe(e){try{return this._subscribe(e)}catch(t){c.a.useDeprecatedSynchronousErrorHandling&&(e.syncErrorThrown=!0,e.syncErrorValue=t),function(e){for(;e;){const{closed:t,destination:n,isStopped:r}=e;if(t||r)return!1;e=n&&n instanceof i.a?n:null}return!0}(e)?e.error(t):console.warn(t)}}forEach(e,t){return new(t=u(t))((t,n)=>{let i;i=this.subscribe(t=>{try{e(t)}catch(r){n(r),i&&i.unsubscribe()}},n,t)})}_subscribe(e){const{source:t}=this;return t&&t.subscribe(e)}[o.a](){return this}pipe(...e){return 0===e.length?this:Object(a.b)(e)(this)}toPromise(e){return new(e=u(e))((e,t)=>{let n;this.subscribe(e=>n=e,e=>t(e),()=>e(n))})}}return e.create=t=>new e(t),e})();function u(e){if(e||(e=c.a.Promise||Promise),!e)throw new Error("no Promise impl found");return e}},HH4o:function(e,t,n){var i=n("tiKp")("iterator"),r=!1;try{var s=0,o={next:function(){return{done:!!s++}},return:function(){r=!0}};o[i]=function(){return this},Array.from(o,(function(){throw 2}))}catch(a){}e.exports=function(e,t){if(!t&&!r)return!1;var n=!1;try{var s={};s[i]=function(){return{next:function(){return{done:n=!0}}}},e(s)}catch(a){}return n}},HP3h:function(e,t,n){!function(e){"use strict";var t={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},n=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},i={s:["\u0623\u0642\u0644 \u0645\u0646 \u062b\u0627\u0646\u064a\u0629","\u062b\u0627\u0646\u064a\u0629 \u0648\u0627\u062d\u062f\u0629",["\u062b\u0627\u0646\u064a\u062a\u0627\u0646","\u062b\u0627\u0646\u064a\u062a\u064a\u0646"],"%d \u062b\u0648\u0627\u0646","%d \u062b\u0627\u0646\u064a\u0629","%d \u062b\u0627\u0646\u064a\u0629"],m:["\u0623\u0642\u0644 \u0645\u0646 \u062f\u0642\u064a\u0642\u0629","\u062f\u0642\u064a\u0642\u0629 \u0648\u0627\u062d\u062f\u0629",["\u062f\u0642\u064a\u0642\u062a\u0627\u0646","\u062f\u0642\u064a\u0642\u062a\u064a\u0646"],"%d \u062f\u0642\u0627\u0626\u0642","%d \u062f\u0642\u064a\u0642\u0629","%d \u062f\u0642\u064a\u0642\u0629"],h:["\u0623\u0642\u0644 \u0645\u0646 \u0633\u0627\u0639\u0629","\u0633\u0627\u0639\u0629 \u0648\u0627\u062d\u062f\u0629",["\u0633\u0627\u0639\u062a\u0627\u0646","\u0633\u0627\u0639\u062a\u064a\u0646"],"%d \u0633\u0627\u0639\u0627\u062a","%d \u0633\u0627\u0639\u0629","%d \u0633\u0627\u0639\u0629"],d:["\u0623\u0642\u0644 \u0645\u0646 \u064a\u0648\u0645","\u064a\u0648\u0645 \u0648\u0627\u062d\u062f",["\u064a\u0648\u0645\u0627\u0646","\u064a\u0648\u0645\u064a\u0646"],"%d \u0623\u064a\u0627\u0645","%d \u064a\u0648\u0645\u064b\u0627","%d \u064a\u0648\u0645"],M:["\u0623\u0642\u0644 \u0645\u0646 \u0634\u0647\u0631","\u0634\u0647\u0631 \u0648\u0627\u062d\u062f",["\u0634\u0647\u0631\u0627\u0646","\u0634\u0647\u0631\u064a\u0646"],"%d \u0623\u0634\u0647\u0631","%d \u0634\u0647\u0631\u0627","%d \u0634\u0647\u0631"],y:["\u0623\u0642\u0644 \u0645\u0646 \u0639\u0627\u0645","\u0639\u0627\u0645 \u0648\u0627\u062d\u062f",["\u0639\u0627\u0645\u0627\u0646","\u0639\u0627\u0645\u064a\u0646"],"%d \u0623\u0639\u0648\u0627\u0645","%d \u0639\u0627\u0645\u064b\u0627","%d \u0639\u0627\u0645"]},r=function(e){return function(t,r,s,o){var a=n(t),c=i[e][n(t)];return 2===a&&(c=c[r?0:1]),c.replace(/%d/i,t)}},s=["\u064a\u0646\u0627\u064a\u0631","\u0641\u0628\u0631\u0627\u064a\u0631","\u0645\u0627\u0631\u0633","\u0623\u0628\u0631\u064a\u0644","\u0645\u0627\u064a\u0648","\u064a\u0648\u0646\u064a\u0648","\u064a\u0648\u0644\u064a\u0648","\u0623\u063a\u0633\u0637\u0633","\u0633\u0628\u062a\u0645\u0628\u0631","\u0623\u0643\u062a\u0648\u0628\u0631","\u0646\u0648\u0641\u0645\u0628\u0631","\u062f\u064a\u0633\u0645\u0628\u0631"];e.defineLocale("ar-ly",{months:s,monthsShort:s,weekdays:"\u0627\u0644\u0623\u062d\u062f_\u0627\u0644\u0625\u062b\u0646\u064a\u0646_\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621_\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621_\u0627\u0644\u062e\u0645\u064a\u0633_\u0627\u0644\u062c\u0645\u0639\u0629_\u0627\u0644\u0633\u0628\u062a".split("_"),weekdaysShort:"\u0623\u062d\u062f_\u0625\u062b\u0646\u064a\u0646_\u062b\u0644\u0627\u062b\u0627\u0621_\u0623\u0631\u0628\u0639\u0627\u0621_\u062e\u0645\u064a\u0633_\u062c\u0645\u0639\u0629_\u0633\u0628\u062a".split("_"),weekdaysMin:"\u062d_\u0646_\u062b_\u0631_\u062e_\u062c_\u0633".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/\u200fM/\u200fYYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/\u0635|\u0645/,isPM:function(e){return"\u0645"===e},meridiem:function(e,t,n){return e<12?"\u0635":"\u0645"},calendar:{sameDay:"[\u0627\u0644\u064a\u0648\u0645 \u0639\u0646\u062f \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextDay:"[\u063a\u062f\u064b\u0627 \u0639\u0646\u062f \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextWeek:"dddd [\u0639\u0646\u062f \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastDay:"[\u0623\u0645\u0633 \u0639\u0646\u062f \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastWeek:"dddd [\u0639\u0646\u062f \u0627\u0644\u0633\u0627\u0639\u0629] LT",sameElse:"L"},relativeTime:{future:"\u0628\u0639\u062f %s",past:"\u0645\u0646\u0630 %s",s:r("s"),ss:r("s"),m:r("m"),mm:r("m"),h:r("h"),hh:r("h"),d:r("d"),dd:r("d"),M:r("M"),MM:r("M"),y:r("y"),yy:r("y")},preparse:function(e){return e.replace(/\u060c/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"\u060c")},week:{dow:6,doy:12}})}(n("wd/R"))},HYAF:function(e,t){e.exports=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e}},Hd5f:function(e,t,n){var i=n("0Dky"),r=n("tiKp"),s=n("LQDL"),o=r("species");e.exports=function(e){return s>=51||!i((function(){var t=[];return(t.constructor={})[o]=function(){return{foo:1}},1!==t[e](Boolean).foo}))}},Hicy:function(e,t,n){"use strict";n.d(t,"a",(function(){return s})),n.d(t,"b",(function(){return o}));var i=n("8Y7J"),r=n("SVse"),s=function(){function e(e,t,n){this._el=e,this._ngZone=t,this.platformId=n,this.clickOutsideEnabled=!0,this.attachOutsideOnClick=!1,this.delayClickOutsideInit=!1,this.emitOnBlur=!1,this.exclude="",this.excludeBeforeClick=!1,this.clickOutsideEvents="",this.clickOutside=new i.o,this._nodesExcluded=[],this._events=["click"],this._initOnClickBody=this._initOnClickBody.bind(this),this._onClickBody=this._onClickBody.bind(this),this._onWindowBlur=this._onWindowBlur.bind(this)}return e.prototype.ngOnInit=function(){Object(r.I)(this.platformId)&&this._init()},e.prototype.ngOnDestroy=function(){Object(r.I)(this.platformId)&&(this._removeClickOutsideListener(),this._removeAttachOutsideOnClickListener(),this._removeWindowBlurListener())},e.prototype.ngOnChanges=function(e){Object(r.I)(this.platformId)&&(e.attachOutsideOnClick||e.exclude||e.emitOnBlur)&&this._init()},e.prototype._init=function(){""!==this.clickOutsideEvents&&(this._events=this.clickOutsideEvents.split(",").map((function(e){return e.trim()}))),this._excludeCheck(),this.attachOutsideOnClick?this._initAttachOutsideOnClickListener():this._initOnClickBody(),this.emitOnBlur&&this._initWindowBlurListener()},e.prototype._initOnClickBody=function(){this.delayClickOutsideInit?setTimeout(this._initClickOutsideListener.bind(this)):this._initClickOutsideListener()},e.prototype._excludeCheck=function(){if(this.exclude)try{var e=Array.from(document.querySelectorAll(this.exclude));e&&(this._nodesExcluded=e)}catch(t){console.error("[ng-click-outside] Check your exclude selector syntax.",t)}},e.prototype._onClickBody=function(e){this.clickOutsideEnabled&&(this.excludeBeforeClick&&this._excludeCheck(),this._el.nativeElement.contains(e.target)||this._shouldExclude(e.target)||(this._emit(e),this.attachOutsideOnClick&&this._removeClickOutsideListener()))},e.prototype._onWindowBlur=function(e){var t=this;setTimeout((function(){document.hidden||t._emit(e)}))},e.prototype._emit=function(e){var t=this;this.clickOutsideEnabled&&this._ngZone.run((function(){return t.clickOutside.emit(e)}))},e.prototype._shouldExclude=function(e){for(var t=0,n=this._nodesExcluded;te&&"number"==typeof e.length&&"function"!=typeof e},I8vh:function(e,t,n){var i=n("ppGB"),r=Math.max,s=Math.min;e.exports=function(e,t){var n=i(e);return n<0?r(n+t,0):s(n,t)}},IBtZ:function(e,t,n){!function(e){"use strict";e.defineLocale("ka",{months:"\u10d8\u10d0\u10dc\u10d5\u10d0\u10e0\u10d8_\u10d7\u10d4\u10d1\u10d4\u10e0\u10d5\u10d0\u10da\u10d8_\u10db\u10d0\u10e0\u10e2\u10d8_\u10d0\u10de\u10e0\u10d8\u10da\u10d8_\u10db\u10d0\u10d8\u10e1\u10d8_\u10d8\u10d5\u10dc\u10d8\u10e1\u10d8_\u10d8\u10d5\u10da\u10d8\u10e1\u10d8_\u10d0\u10d2\u10d5\u10d8\u10e1\u10e2\u10dd_\u10e1\u10d4\u10e5\u10e2\u10d4\u10db\u10d1\u10d4\u10e0\u10d8_\u10dd\u10e5\u10e2\u10dd\u10db\u10d1\u10d4\u10e0\u10d8_\u10dc\u10dd\u10d4\u10db\u10d1\u10d4\u10e0\u10d8_\u10d3\u10d4\u10d9\u10d4\u10db\u10d1\u10d4\u10e0\u10d8".split("_"),monthsShort:"\u10d8\u10d0\u10dc_\u10d7\u10d4\u10d1_\u10db\u10d0\u10e0_\u10d0\u10de\u10e0_\u10db\u10d0\u10d8_\u10d8\u10d5\u10dc_\u10d8\u10d5\u10da_\u10d0\u10d2\u10d5_\u10e1\u10d4\u10e5_\u10dd\u10e5\u10e2_\u10dc\u10dd\u10d4_\u10d3\u10d4\u10d9".split("_"),weekdays:{standalone:"\u10d9\u10d5\u10d8\u10e0\u10d0_\u10dd\u10e0\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8_\u10e1\u10d0\u10db\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8_\u10dd\u10d7\u10ee\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8_\u10ee\u10e3\u10d7\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8_\u10de\u10d0\u10e0\u10d0\u10e1\u10d9\u10d4\u10d5\u10d8_\u10e8\u10d0\u10d1\u10d0\u10d7\u10d8".split("_"),format:"\u10d9\u10d5\u10d8\u10e0\u10d0\u10e1_\u10dd\u10e0\u10e8\u10d0\u10d1\u10d0\u10d7\u10e1_\u10e1\u10d0\u10db\u10e8\u10d0\u10d1\u10d0\u10d7\u10e1_\u10dd\u10d7\u10ee\u10e8\u10d0\u10d1\u10d0\u10d7\u10e1_\u10ee\u10e3\u10d7\u10e8\u10d0\u10d1\u10d0\u10d7\u10e1_\u10de\u10d0\u10e0\u10d0\u10e1\u10d9\u10d4\u10d5\u10e1_\u10e8\u10d0\u10d1\u10d0\u10d7\u10e1".split("_"),isFormat:/(\u10ec\u10d8\u10dc\u10d0|\u10e8\u10d4\u10db\u10d3\u10d4\u10d2)/},weekdaysShort:"\u10d9\u10d5\u10d8_\u10dd\u10e0\u10e8_\u10e1\u10d0\u10db_\u10dd\u10d7\u10ee_\u10ee\u10e3\u10d7_\u10de\u10d0\u10e0_\u10e8\u10d0\u10d1".split("_"),weekdaysMin:"\u10d9\u10d5_\u10dd\u10e0_\u10e1\u10d0_\u10dd\u10d7_\u10ee\u10e3_\u10de\u10d0_\u10e8\u10d0".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[\u10d3\u10e6\u10d4\u10e1] LT[-\u10d6\u10d4]",nextDay:"[\u10ee\u10d5\u10d0\u10da] LT[-\u10d6\u10d4]",lastDay:"[\u10d2\u10e3\u10e8\u10d8\u10dc] LT[-\u10d6\u10d4]",nextWeek:"[\u10e8\u10d4\u10db\u10d3\u10d4\u10d2] dddd LT[-\u10d6\u10d4]",lastWeek:"[\u10ec\u10d8\u10dc\u10d0] dddd LT-\u10d6\u10d4",sameElse:"L"},relativeTime:{future:function(e){return e.replace(/(\u10ec\u10d0\u10db|\u10ec\u10e3\u10d7|\u10e1\u10d0\u10d0\u10d7|\u10ec\u10d4\u10da|\u10d3\u10e6|\u10d7\u10d5)(\u10d8|\u10d4)/,(function(e,t,n){return"\u10d8"===n?t+"\u10e8\u10d8":t+n+"\u10e8\u10d8"}))},past:function(e){return/(\u10ec\u10d0\u10db\u10d8|\u10ec\u10e3\u10d7\u10d8|\u10e1\u10d0\u10d0\u10d7\u10d8|\u10d3\u10e6\u10d4|\u10d7\u10d5\u10d4)/.test(e)?e.replace(/(\u10d8|\u10d4)$/,"\u10d8\u10e1 \u10ec\u10d8\u10dc"):/\u10ec\u10d4\u10da\u10d8/.test(e)?e.replace(/\u10ec\u10d4\u10da\u10d8$/,"\u10ec\u10da\u10d8\u10e1 \u10ec\u10d8\u10dc"):e},s:"\u10e0\u10d0\u10db\u10d3\u10d4\u10dc\u10d8\u10db\u10d4 \u10ec\u10d0\u10db\u10d8",ss:"%d \u10ec\u10d0\u10db\u10d8",m:"\u10ec\u10e3\u10d7\u10d8",mm:"%d \u10ec\u10e3\u10d7\u10d8",h:"\u10e1\u10d0\u10d0\u10d7\u10d8",hh:"%d \u10e1\u10d0\u10d0\u10d7\u10d8",d:"\u10d3\u10e6\u10d4",dd:"%d \u10d3\u10e6\u10d4",M:"\u10d7\u10d5\u10d4",MM:"%d \u10d7\u10d5\u10d4",y:"\u10ec\u10d4\u10da\u10d8",yy:"%d \u10ec\u10d4\u10da\u10d8"},dayOfMonthOrdinalParse:/0|1-\u10da\u10d8|\u10db\u10d4-\d{1,2}|\d{1,2}-\u10d4/,ordinal:function(e){return 0===e?e:1===e?e+"-\u10da\u10d8":e<20||e<=100&&e%20==0||e%100==0?"\u10db\u10d4-"+e:e+"-\u10d4"},week:{dow:1,doy:7}})}(n("wd/R"))},IZUe:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");let o=(()=>{class e{constructor(e){this.elementRef=e,this.focus=!0}ngAfterViewInit(){const e=this.elementRef.nativeElement;this.focus&&r.a.isFunction(e.focus)&&e.focus()}set autofocus(e){r.a.isBoolean(e)?this.focus=e:r.a.isFunction(e)&&(this.focus=e())}}return e.\u0275fac=function(t){return new(t||e)(s.Mb(s.m))},e.\u0275dir=s.Hb({type:e,selectors:[["","autofocus",""]],inputs:{autofocus:"autofocus"}}),e})()},Iab2:function(e,t,n){var i,r;void 0===(r="function"==typeof(i=function(){"use strict";function t(e,t,n){var i=new XMLHttpRequest;i.open("GET",e),i.responseType="blob",i.onload=function(){s(i.response,t,n)},i.onerror=function(){console.error("could not download file")},i.send()}function n(e){var t=new XMLHttpRequest;t.open("HEAD",e,!1);try{t.send()}catch(e){}return 200<=t.status&&299>=t.status}function i(e){try{e.dispatchEvent(new MouseEvent("click"))}catch(t){var n=document.createEvent("MouseEvents");n.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),e.dispatchEvent(n)}}var r="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,s=r.saveAs||("object"!=typeof window||window!==r?function(){}:"download"in HTMLAnchorElement.prototype?function(e,s,o){var a=r.URL||r.webkitURL,c=document.createElement("a");c.download=s=s||e.name||"download",c.rel="noopener","string"==typeof e?(c.href=e,c.origin===location.origin?i(c):n(c.href)?t(e,s,o):i(c,c.target="_blank")):(c.href=a.createObjectURL(e),setTimeout((function(){a.revokeObjectURL(c.href)}),4e4),setTimeout((function(){i(c)}),0))}:"msSaveOrOpenBlob"in navigator?function(e,r,s){if(r=r||e.name||"download","string"!=typeof e)navigator.msSaveOrOpenBlob(function(e,t){return void 0===t?t={autoBom:!1}:"object"!=typeof t&&(console.warn("Deprecated: Expected third argument to be a object"),t={autoBom:!t}),t.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)?new Blob(["\ufeff",e],{type:e.type}):e}(e,s),r);else if(n(e))t(e,r,s);else{var o=document.createElement("a");o.href=e,o.target="_blank",setTimeout((function(){i(o)}))}}:function(e,n,i,s){if((s=s||open("","_blank"))&&(s.document.title=s.document.body.innerText="downloading..."),"string"==typeof e)return t(e,n,i);var o="application/octet-stream"===e.type,a=/constructor/i.test(r.HTMLElement)||r.safari,c=/CriOS\/[\d]+/.test(navigator.userAgent);if((c||o&&a)&&"object"==typeof FileReader){var l=new FileReader;l.onloadend=function(){var e=l.result;e=c?e:e.replace(/^data:[^;]*;/,"data:attachment/file;"),s?s.location.href=e:location=e,s=null},l.readAsDataURL(e)}else{var u=r.URL||r.webkitURL,d=u.createObjectURL(e);s?s.location=d:location.href=d,s=null,setTimeout((function(){u.revokeObjectURL(d)}),4e4)}});r.saveAs=s.saveAs=s,e.exports=s})?i.apply(t,[]):i)||(e.exports=r)},IheW:function(e,t,n){"use strict";n.d(t,"a",(function(){return C})),n.d(t,"b",(function(){return D})),n.d(t,"c",(function(){return $})),n.d(t,"d",(function(){return x})),n.d(t,"e",(function(){return m}));var i=n("8Y7J"),r=n("LRne"),s=n("HDdC"),o=n("bOdf"),a=n("pLZG"),c=n("lJxs"),l=n("SVse");class u{}class d{}class h{constructor(e){this.normalizedNames=new Map,this.lazyUpdate=null,e?this.lazyInit="string"==typeof e?()=>{this.headers=new Map,e.split("\n").forEach(e=>{const t=e.indexOf(":");if(t>0){const n=e.slice(0,t),i=n.toLowerCase(),r=e.slice(t+1).trim();this.maybeSetNormalizedName(n,i),this.headers.has(i)?this.headers.get(i).push(r):this.headers.set(i,[r])}})}:()=>{this.headers=new Map,Object.keys(e).forEach(t=>{let n=e[t];const i=t.toLowerCase();"string"==typeof n&&(n=[n]),n.length>0&&(this.headers.set(i,n),this.maybeSetNormalizedName(t,i))})}:this.headers=new Map}has(e){return this.init(),this.headers.has(e.toLowerCase())}get(e){this.init();const t=this.headers.get(e.toLowerCase());return t&&t.length>0?t[0]:null}keys(){return this.init(),Array.from(this.normalizedNames.values())}getAll(e){return this.init(),this.headers.get(e.toLowerCase())||null}append(e,t){return this.clone({name:e,value:t,op:"a"})}set(e,t){return this.clone({name:e,value:t,op:"s"})}delete(e,t){return this.clone({name:e,value:t,op:"d"})}maybeSetNormalizedName(e,t){this.normalizedNames.has(t)||this.normalizedNames.set(t,e)}init(){this.lazyInit&&(this.lazyInit instanceof h?this.copyFrom(this.lazyInit):this.lazyInit(),this.lazyInit=null,this.lazyUpdate&&(this.lazyUpdate.forEach(e=>this.applyUpdate(e)),this.lazyUpdate=null))}copyFrom(e){e.init(),Array.from(e.headers.keys()).forEach(t=>{this.headers.set(t,e.headers.get(t)),this.normalizedNames.set(t,e.normalizedNames.get(t))})}clone(e){const t=new h;return t.lazyInit=this.lazyInit&&this.lazyInit instanceof h?this.lazyInit:this,t.lazyUpdate=(this.lazyUpdate||[]).concat([e]),t}applyUpdate(e){const t=e.name.toLowerCase();switch(e.op){case"a":case"s":let n=e.value;if("string"==typeof n&&(n=[n]),0===n.length)return;this.maybeSetNormalizedName(e.name,t);const i=("a"===e.op?this.headers.get(t):void 0)||[];i.push(...n),this.headers.set(t,i);break;case"d":const r=e.value;if(r){let e=this.headers.get(t);if(!e)return;e=e.filter(e=>-1===r.indexOf(e)),0===e.length?(this.headers.delete(t),this.normalizedNames.delete(t)):this.headers.set(t,e)}else this.headers.delete(t),this.normalizedNames.delete(t)}}forEach(e){this.init(),Array.from(this.normalizedNames.keys()).forEach(t=>e(this.normalizedNames.get(t),this.headers.get(t)))}}class f{encodeKey(e){return p(e)}encodeValue(e){return p(e)}decodeKey(e){return decodeURIComponent(e)}decodeValue(e){return decodeURIComponent(e)}}function p(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/gi,"$").replace(/%2C/gi,",").replace(/%3B/gi,";").replace(/%2B/gi,"+").replace(/%3D/gi,"=").replace(/%3F/gi,"?").replace(/%2F/gi,"/")}class m{constructor(e={}){if(this.updates=null,this.cloneFrom=null,this.encoder=e.encoder||new f,e.fromString){if(e.fromObject)throw new Error("Cannot specify both fromString and fromObject.");this.map=function(e,t){const n=new Map;return e.length>0&&e.split("&").forEach(e=>{const i=e.indexOf("="),[r,s]=-1==i?[t.decodeKey(e),""]:[t.decodeKey(e.slice(0,i)),t.decodeValue(e.slice(i+1))],o=n.get(r)||[];o.push(s),n.set(r,o)}),n}(e.fromString,this.encoder)}else e.fromObject?(this.map=new Map,Object.keys(e.fromObject).forEach(t=>{const n=e.fromObject[t];this.map.set(t,Array.isArray(n)?n:[n])})):this.map=null}has(e){return this.init(),this.map.has(e)}get(e){this.init();const t=this.map.get(e);return t?t[0]:null}getAll(e){return this.init(),this.map.get(e)||null}keys(){return this.init(),Array.from(this.map.keys())}append(e,t){return this.clone({param:e,value:t,op:"a"})}set(e,t){return this.clone({param:e,value:t,op:"s"})}delete(e,t){return this.clone({param:e,value:t,op:"d"})}toString(){return this.init(),this.keys().map(e=>{const t=this.encoder.encodeKey(e);return this.map.get(e).map(e=>t+"="+this.encoder.encodeValue(e)).join("&")}).filter(e=>""!==e).join("&")}clone(e){const t=new m({encoder:this.encoder});return t.cloneFrom=this.cloneFrom||this,t.updates=(this.updates||[]).concat([e]),t}init(){null===this.map&&(this.map=new Map),null!==this.cloneFrom&&(this.cloneFrom.init(),this.cloneFrom.keys().forEach(e=>this.map.set(e,this.cloneFrom.map.get(e))),this.updates.forEach(e=>{switch(e.op){case"a":case"s":const t=("a"===e.op?this.map.get(e.param):void 0)||[];t.push(e.value),this.map.set(e.param,t);break;case"d":if(void 0===e.value){this.map.delete(e.param);break}{let t=this.map.get(e.param)||[];const n=t.indexOf(e.value);-1!==n&&t.splice(n,1),t.length>0?this.map.set(e.param,t):this.map.delete(e.param)}}}),this.cloneFrom=this.updates=null)}}function b(e){return"undefined"!=typeof ArrayBuffer&&e instanceof ArrayBuffer}function g(e){return"undefined"!=typeof Blob&&e instanceof Blob}function _(e){return"undefined"!=typeof FormData&&e instanceof FormData}class y{constructor(e,t,n,i){let r;if(this.url=t,this.body=null,this.reportProgress=!1,this.withCredentials=!1,this.responseType="json",this.method=e.toUpperCase(),function(e){switch(e){case"DELETE":case"GET":case"HEAD":case"OPTIONS":case"JSONP":return!1;default:return!0}}(this.method)||i?(this.body=void 0!==n?n:null,r=i):r=n,r&&(this.reportProgress=!!r.reportProgress,this.withCredentials=!!r.withCredentials,r.responseType&&(this.responseType=r.responseType),r.headers&&(this.headers=r.headers),r.params&&(this.params=r.params)),this.headers||(this.headers=new h),this.params){const e=this.params.toString();if(0===e.length)this.urlWithParams=t;else{const n=t.indexOf("?");this.urlWithParams=t+(-1===n?"?":nt.set(n,e.setHeaders[n]),a)),e.setParams&&(c=Object.keys(e.setParams).reduce((t,n)=>t.set(n,e.setParams[n]),c)),new y(t,n,r,{params:c,headers:a,reportProgress:o,responseType:i,withCredentials:s})}}var v=function(e){return e[e.Sent=0]="Sent",e[e.UploadProgress=1]="UploadProgress",e[e.ResponseHeader=2]="ResponseHeader",e[e.DownloadProgress=3]="DownloadProgress",e[e.Response=4]="Response",e[e.User=5]="User",e}({});class w{constructor(e,t=200,n="OK"){this.headers=e.headers||new h,this.status=void 0!==e.status?e.status:t,this.statusText=e.statusText||n,this.url=e.url||null,this.ok=this.status>=200&&this.status<300}}class S extends w{constructor(e={}){super(e),this.type=v.ResponseHeader}clone(e={}){return new S({headers:e.headers||this.headers,status:void 0!==e.status?e.status:this.status,statusText:e.statusText||this.statusText,url:e.url||this.url||void 0})}}class M extends w{constructor(e={}){super(e),this.type=v.Response,this.body=void 0!==e.body?e.body:null}clone(e={}){return new M({body:void 0!==e.body?e.body:this.body,headers:e.headers||this.headers,status:void 0!==e.status?e.status:this.status,statusText:e.statusText||this.statusText,url:e.url||this.url||void 0})}}class x extends w{constructor(e){super(e,0,"Unknown Error"),this.name="HttpErrorResponse",this.ok=!1,this.message=this.status>=200&&this.status<300?"Http failure during parsing for "+(e.url||"(unknown url)"):`Http failure response for ${e.url||"(unknown url)"}: ${e.status} ${e.statusText}`,this.error=e.error||null}}function k(e,t){return{body:t,headers:e.headers,observe:e.observe,params:e.params,reportProgress:e.reportProgress,responseType:e.responseType,withCredentials:e.withCredentials}}let D=(()=>{class e{constructor(e){this.handler=e}request(e,t,n={}){let i;if(e instanceof y)i=e;else{let r=void 0;r=n.headers instanceof h?n.headers:new h(n.headers);let s=void 0;n.params&&(s=n.params instanceof m?n.params:new m({fromObject:n.params})),i=new y(e,t,void 0!==n.body?n.body:null,{headers:r,params:s,reportProgress:n.reportProgress,responseType:n.responseType||"json",withCredentials:n.withCredentials})}const s=Object(r.a)(i).pipe(Object(o.a)(e=>this.handler.handle(e)));if(e instanceof y||"events"===n.observe)return s;const l=s.pipe(Object(a.a)(e=>e instanceof M));switch(n.observe||"body"){case"body":switch(i.responseType){case"arraybuffer":return l.pipe(Object(c.a)(e=>{if(null!==e.body&&!(e.body instanceof ArrayBuffer))throw new Error("Response is not an ArrayBuffer.");return e.body}));case"blob":return l.pipe(Object(c.a)(e=>{if(null!==e.body&&!(e.body instanceof Blob))throw new Error("Response is not a Blob.");return e.body}));case"text":return l.pipe(Object(c.a)(e=>{if(null!==e.body&&"string"!=typeof e.body)throw new Error("Response is not a string.");return e.body}));case"json":default:return l.pipe(Object(c.a)(e=>e.body))}case"response":return l;default:throw new Error(`Unreachable: unhandled observe type ${n.observe}}`)}}delete(e,t={}){return this.request("DELETE",e,t)}get(e,t={}){return this.request("GET",e,t)}head(e,t={}){return this.request("HEAD",e,t)}jsonp(e,t){return this.request("JSONP",e,{params:(new m).append(t,"JSONP_CALLBACK"),observe:"body",responseType:"json"})}options(e,t={}){return this.request("OPTIONS",e,t)}patch(e,t,n={}){return this.request("PATCH",e,k(n,t))}post(e,t,n={}){return this.request("POST",e,k(n,t))}put(e,t,n={}){return this.request("PUT",e,k(n,t))}}return e.\u0275fac=function(t){return new(t||e)(i.dc(u))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})();class T{constructor(e,t){this.next=e,this.interceptor=t}handle(e){return this.interceptor.intercept(e,this.next)}}const C=new i.r("HTTP_INTERCEPTORS");let O=(()=>{class e{intercept(e,t){return t.handle(e)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})();const L=/^\)\]\}',?\n/;class R{}let E=(()=>{class e{constructor(){}build(){return new XMLHttpRequest}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})(),A=(()=>{class e{constructor(e){this.xhrFactory=e}handle(e){if("JSONP"===e.method)throw new Error("Attempted to construct Jsonp request without HttpClientJsonpModule installed.");return new s.a(t=>{const n=this.xhrFactory.build();if(n.open(e.method,e.urlWithParams),e.withCredentials&&(n.withCredentials=!0),e.headers.forEach((e,t)=>n.setRequestHeader(e,t.join(","))),e.headers.has("Accept")||n.setRequestHeader("Accept","application/json, text/plain, */*"),!e.headers.has("Content-Type")){const t=e.detectContentTypeHeader();null!==t&&n.setRequestHeader("Content-Type",t)}if(e.responseType){const t=e.responseType.toLowerCase();n.responseType="json"!==t?t:"text"}const i=e.serializeBody();let r=null;const s=()=>{if(null!==r)return r;const t=1223===n.status?204:n.status,i=n.statusText||"OK",s=new h(n.getAllResponseHeaders()),o=function(e){return"responseURL"in e&&e.responseURL?e.responseURL:/^X-Request-URL:/m.test(e.getAllResponseHeaders())?e.getResponseHeader("X-Request-URL"):null}(n)||e.url;return r=new S({headers:s,status:t,statusText:i,url:o}),r},o=()=>{let{headers:i,status:r,statusText:o,url:a}=s(),c=null;204!==r&&(c=void 0===n.response?n.responseText:n.response),0===r&&(r=c?200:0);let l=r>=200&&r<300;if("json"===e.responseType&&"string"==typeof c){const e=c;c=c.replace(L,"");try{c=""!==c?JSON.parse(c):null}catch(u){c=e,l&&(l=!1,c={error:u,text:c})}}l?(t.next(new M({body:c,headers:i,status:r,statusText:o,url:a||void 0})),t.complete()):t.error(new x({error:c,headers:i,status:r,statusText:o,url:a||void 0}))},a=e=>{const{url:i}=s(),r=new x({error:e,status:n.status||0,statusText:n.statusText||"Unknown Error",url:i||void 0});t.error(r)};let c=!1;const l=i=>{c||(t.next(s()),c=!0);let r={type:v.DownloadProgress,loaded:i.loaded};i.lengthComputable&&(r.total=i.total),"text"===e.responseType&&n.responseText&&(r.partialText=n.responseText),t.next(r)},u=e=>{let n={type:v.UploadProgress,loaded:e.loaded};e.lengthComputable&&(n.total=e.total),t.next(n)};return n.addEventListener("load",o),n.addEventListener("error",a),e.reportProgress&&(n.addEventListener("progress",l),null!==i&&n.upload&&n.upload.addEventListener("progress",u)),n.send(i),t.next({type:v.Sent}),()=>{n.removeEventListener("error",a),n.removeEventListener("load",o),e.reportProgress&&(n.removeEventListener("progress",l),null!==i&&n.upload&&n.upload.removeEventListener("progress",u)),n.readyState!==n.DONE&&n.abort()}})}}return e.\u0275fac=function(t){return new(t||e)(i.dc(R))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})();const I=new i.r("XSRF_COOKIE_NAME"),P=new i.r("XSRF_HEADER_NAME");class j{}let N=(()=>{class e{constructor(e,t,n){this.doc=e,this.platform=t,this.cookieName=n,this.lastCookieString="",this.lastToken=null,this.parseCount=0}getToken(){if("server"===this.platform)return null;const e=this.doc.cookie||"";return e!==this.lastCookieString&&(this.parseCount++,this.lastToken=Object(l.M)(e,this.cookieName),this.lastCookieString=e),this.lastToken}}return e.\u0275fac=function(t){return new(t||e)(i.dc(l.d),i.dc(i.C),i.dc(I))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})(),F=(()=>{class e{constructor(e,t){this.tokenService=e,this.headerName=t}intercept(e,t){const n=e.url.toLowerCase();if("GET"===e.method||"HEAD"===e.method||n.startsWith("http://")||n.startsWith("https://"))return t.handle(e);const i=this.tokenService.getToken();return null===i||e.headers.has(this.headerName)||(e=e.clone({headers:e.headers.set(this.headerName,i)})),t.handle(e)}}return e.\u0275fac=function(t){return new(t||e)(i.dc(j),i.dc(P))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})(),Y=(()=>{class e{constructor(e,t){this.backend=e,this.injector=t,this.chain=null}handle(e){if(null===this.chain){const e=this.injector.get(C,[]);this.chain=e.reduceRight((e,t)=>new T(e,t),this.backend)}return this.chain.handle(e)}}return e.\u0275fac=function(t){return new(t||e)(i.dc(d),i.dc(i.s))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})(),z=(()=>{class e{static disable(){return{ngModule:e,providers:[{provide:F,useClass:O}]}}static withOptions(t={}){return{ngModule:e,providers:[t.cookieName?{provide:I,useValue:t.cookieName}:[],t.headerName?{provide:P,useValue:t.headerName}:[]]}}}return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},providers:[F,{provide:C,useExisting:F,multi:!0},{provide:j,useClass:N},{provide:I,useValue:"XSRF-TOKEN"},{provide:P,useValue:"X-XSRF-TOKEN"}]}),e})(),$=(()=>{class e{}return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},providers:[D,{provide:u,useClass:Y},A,{provide:d,useExisting:A},E,{provide:R,useExisting:E}],imports:[[z.withOptions({cookieName:"XSRF-TOKEN",headerName:"X-XSRF-TOKEN"})]]}),e})()},IjjT:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));let i=(()=>{class e{constructor(t,n=e.now){this.SchedulerAction=t,this.now=n}schedule(e,t=0,n){return new this.SchedulerAction(this,e).schedule(n,t)}}return e.now=()=>Date.now(),e})();class r extends i{constructor(e,t=i.now){super(e,()=>r.delegate&&r.delegate!==this?r.delegate.now():t()),this.actions=[],this.active=!1,this.scheduled=void 0}schedule(e,t=0,n){return r.delegate&&r.delegate!==this?r.delegate.schedule(e,t,n):super.schedule(e,t,n)}flush(e){const{actions:t}=this;if(this.active)return void t.push(e);let n;this.active=!0;do{if(n=e.execute(e.state,e.delay))break}while(e=t.shift());if(this.active=!1,n){for(;e=t.shift();)e.unsubscribe();throw n}}}},ImZN:function(e,t,n){var i=n("glrk"),r=n("6VoE"),s=n("UMSQ"),o=n("A2ZE"),a=n("NaFW"),c=n("KmKo"),l=function(e,t){this.stopped=e,this.result=t};e.exports=function(e,t,n){var u,d,h,f,p,m,b,g=!(!n||!n.AS_ENTRIES),_=!(!n||!n.IS_ITERATOR),y=!(!n||!n.INTERRUPTED),v=o(t,n&&n.that,1+g+y),w=function(e){return u&&c(u),new l(!0,e)},S=function(e){return g?(i(e),y?v(e[0],e[1],w):v(e[0],e[1])):y?v(e,w):v(e)};if(_)u=e;else{if("function"!=typeof(d=a(e)))throw TypeError("Target is not iterable");if(r(d)){for(h=0,f=s(e.length);f>h;h++)if((p=S(e[h]))&&p instanceof l)return p;return new l(!1)}u=d.call(e)}for(m=u.next;!(b=m.call(u)).done;){try{p=S(b.value)}catch(M){throw c(u),M}if("object"==typeof p&&p&&p instanceof l)return p}return new l(!1)}},"Ivi+":function(e,t,n){!function(e){"use strict";e.defineLocale("ko",{months:"1\uc6d4_2\uc6d4_3\uc6d4_4\uc6d4_5\uc6d4_6\uc6d4_7\uc6d4_8\uc6d4_9\uc6d4_10\uc6d4_11\uc6d4_12\uc6d4".split("_"),monthsShort:"1\uc6d4_2\uc6d4_3\uc6d4_4\uc6d4_5\uc6d4_6\uc6d4_7\uc6d4_8\uc6d4_9\uc6d4_10\uc6d4_11\uc6d4_12\uc6d4".split("_"),weekdays:"\uc77c\uc694\uc77c_\uc6d4\uc694\uc77c_\ud654\uc694\uc77c_\uc218\uc694\uc77c_\ubaa9\uc694\uc77c_\uae08\uc694\uc77c_\ud1a0\uc694\uc77c".split("_"),weekdaysShort:"\uc77c_\uc6d4_\ud654_\uc218_\ubaa9_\uae08_\ud1a0".split("_"),weekdaysMin:"\uc77c_\uc6d4_\ud654_\uc218_\ubaa9_\uae08_\ud1a0".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY\ub144 MMMM D\uc77c",LLL:"YYYY\ub144 MMMM D\uc77c A h:mm",LLLL:"YYYY\ub144 MMMM D\uc77c dddd A h:mm",l:"YYYY.MM.DD.",ll:"YYYY\ub144 MMMM D\uc77c",lll:"YYYY\ub144 MMMM D\uc77c A h:mm",llll:"YYYY\ub144 MMMM D\uc77c dddd A h:mm"},calendar:{sameDay:"\uc624\ub298 LT",nextDay:"\ub0b4\uc77c LT",nextWeek:"dddd LT",lastDay:"\uc5b4\uc81c LT",lastWeek:"\uc9c0\ub09c\uc8fc dddd LT",sameElse:"L"},relativeTime:{future:"%s \ud6c4",past:"%s \uc804",s:"\uba87 \ucd08",ss:"%d\ucd08",m:"1\ubd84",mm:"%d\ubd84",h:"\ud55c \uc2dc\uac04",hh:"%d\uc2dc\uac04",d:"\ud558\ub8e8",dd:"%d\uc77c",M:"\ud55c \ub2ec",MM:"%d\ub2ec",y:"\uc77c \ub144",yy:"%d\ub144"},dayOfMonthOrdinalParse:/\d{1,2}(\uc77c|\uc6d4|\uc8fc)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"\uc77c";case"M":return e+"\uc6d4";case"w":case"W":return e+"\uc8fc";default:return e}},meridiemParse:/\uc624\uc804|\uc624\ud6c4/,isPM:function(e){return"\uc624\ud6c4"===e},meridiem:function(e,t,n){return e<12?"\uc624\uc804":"\uc624\ud6c4"}})}(n("wd/R"))},IzCI:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("aXbf"),r=n("8Y7J");let s=(()=>{class e{constructor(e){this.formatter=e}transform(e){return this.formatter.format_number(e,1024,["B/s","kB/s","MB/s","GB/s","TB/s","PB/s","EB/s","ZB/s","YB/s"])}}return e.\u0275fac=function(t){return new(t||e)(r.Mb(i.a))},e.\u0275pipe=r.Lb({name:"dimlessBinaryPerSecond",type:e,pure:!0}),e})()},IzEk:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("7o/Q"),r=n("4I5i"),s=n("EY2u");function o(e){return t=>0===e?Object(s.b)():t.lift(new a(e))}class a{constructor(e){if(this.total=e,this.total<0)throw new r.a}call(e,t){return t.subscribe(new c(e,this.total))}}class c extends i.a{constructor(e,t){super(e),this.total=t,this.count=0}_next(e){const t=this.total,n=++this.count;n<=t&&(this.destination.next(e),n===t&&(this.destination.complete(),this.unsubscribe()))}}},IzLi:function(e,t,n){"use strict";t.a=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},JBy8:function(e,t,n){var i=n("yoRg"),r=n("eDl+").concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return i(e,r)}},"JCF/":function(e,t,n){!function(e){"use strict";var t={1:"\u0661",2:"\u0662",3:"\u0663",4:"\u0664",5:"\u0665",6:"\u0666",7:"\u0667",8:"\u0668",9:"\u0669",0:"\u0660"},n={"\u0661":"1","\u0662":"2","\u0663":"3","\u0664":"4","\u0665":"5","\u0666":"6","\u0667":"7","\u0668":"8","\u0669":"9","\u0660":"0"},i=["\u06a9\u0627\u0646\u0648\u0646\u06cc \u062f\u0648\u0648\u06d5\u0645","\u0634\u0648\u0628\u0627\u062a","\u0626\u0627\u0632\u0627\u0631","\u0646\u06cc\u0633\u0627\u0646","\u0626\u0627\u06cc\u0627\u0631","\u062d\u0648\u0632\u06d5\u06cc\u0631\u0627\u0646","\u062a\u06d5\u0645\u0645\u0648\u0632","\u0626\u0627\u0628","\u0626\u06d5\u06cc\u0644\u0648\u0648\u0644","\u062a\u0634\u0631\u06cc\u0646\u06cc \u06cc\u06d5\u0643\u06d5\u0645","\u062a\u0634\u0631\u06cc\u0646\u06cc \u062f\u0648\u0648\u06d5\u0645","\u0643\u0627\u0646\u0648\u0646\u06cc \u06cc\u06d5\u06a9\u06d5\u0645"];e.defineLocale("ku",{months:i,monthsShort:i,weekdays:"\u06cc\u0647\u200c\u0643\u0634\u0647\u200c\u0645\u0645\u0647\u200c_\u062f\u0648\u0648\u0634\u0647\u200c\u0645\u0645\u0647\u200c_\u0633\u06ce\u0634\u0647\u200c\u0645\u0645\u0647\u200c_\u0686\u0648\u0627\u0631\u0634\u0647\u200c\u0645\u0645\u0647\u200c_\u067e\u06ce\u0646\u062c\u0634\u0647\u200c\u0645\u0645\u0647\u200c_\u0647\u0647\u200c\u06cc\u0646\u06cc_\u0634\u0647\u200c\u0645\u0645\u0647\u200c".split("_"),weekdaysShort:"\u06cc\u0647\u200c\u0643\u0634\u0647\u200c\u0645_\u062f\u0648\u0648\u0634\u0647\u200c\u0645_\u0633\u06ce\u0634\u0647\u200c\u0645_\u0686\u0648\u0627\u0631\u0634\u0647\u200c\u0645_\u067e\u06ce\u0646\u062c\u0634\u0647\u200c\u0645_\u0647\u0647\u200c\u06cc\u0646\u06cc_\u0634\u0647\u200c\u0645\u0645\u0647\u200c".split("_"),weekdaysMin:"\u06cc_\u062f_\u0633_\u0686_\u067e_\u0647_\u0634".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/\u0626\u06ce\u0648\u0627\u0631\u0647\u200c|\u0628\u0647\u200c\u06cc\u0627\u0646\u06cc/,isPM:function(e){return/\u0626\u06ce\u0648\u0627\u0631\u0647\u200c/.test(e)},meridiem:function(e,t,n){return e<12?"\u0628\u0647\u200c\u06cc\u0627\u0646\u06cc":"\u0626\u06ce\u0648\u0627\u0631\u0647\u200c"},calendar:{sameDay:"[\u0626\u0647\u200c\u0645\u0631\u06c6 \u0643\u0627\u062a\u0698\u0645\u06ce\u0631] LT",nextDay:"[\u0628\u0647\u200c\u06cc\u0627\u0646\u06cc \u0643\u0627\u062a\u0698\u0645\u06ce\u0631] LT",nextWeek:"dddd [\u0643\u0627\u062a\u0698\u0645\u06ce\u0631] LT",lastDay:"[\u062f\u0648\u06ce\u0646\u06ce \u0643\u0627\u062a\u0698\u0645\u06ce\u0631] LT",lastWeek:"dddd [\u0643\u0627\u062a\u0698\u0645\u06ce\u0631] LT",sameElse:"L"},relativeTime:{future:"\u0644\u0647\u200c %s",past:"%s",s:"\u0686\u0647\u200c\u0646\u062f \u0686\u0631\u0643\u0647\u200c\u06cc\u0647\u200c\u0643",ss:"\u0686\u0631\u0643\u0647\u200c %d",m:"\u06cc\u0647\u200c\u0643 \u062e\u0648\u0644\u0647\u200c\u0643",mm:"%d \u062e\u0648\u0644\u0647\u200c\u0643",h:"\u06cc\u0647\u200c\u0643 \u0643\u0627\u062a\u0698\u0645\u06ce\u0631",hh:"%d \u0643\u0627\u062a\u0698\u0645\u06ce\u0631",d:"\u06cc\u0647\u200c\u0643 \u0695\u06c6\u0698",dd:"%d \u0695\u06c6\u0698",M:"\u06cc\u0647\u200c\u0643 \u0645\u0627\u0646\u06af",MM:"%d \u0645\u0627\u0646\u06af",y:"\u06cc\u0647\u200c\u0643 \u0633\u0627\u06b5",yy:"%d \u0633\u0627\u06b5"},preparse:function(e){return e.replace(/[\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u0660]/g,(function(e){return n[e]})).replace(/\u060c/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"\u060c")},week:{dow:6,doy:12}})}(n("wd/R"))},JIr8:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("zx2A");function r(e){return function(t){const n=new s(e),i=t.lift(n);return n.caught=i}}class s{constructor(e){this.selector=e}call(e,t){return t.subscribe(new o(e,this.selector,this.caught))}}class o extends i.b{constructor(e,t,n){super(e),this.selector=t,this.caught=n}error(e){if(!this.isStopped){let n;try{n=this.selector(e,this.caught)}catch(t){return void super.error(t)}this._unsubscribeAndRecycle();const r=new i.a(this);this.add(r);const s=Object(i.c)(n,r);s!==r&&this.add(s)}}}},"JK/P":function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("8Y7J"),r=n("G0yt");let s=(()=>{class e{constructor(e){this.modal=e}show(e,t,n){const i=this.modal.open(e,n);return t&&Object.assign(i.componentInstance,t),i}dismissAll(){this.modal.dismissAll()}hasOpenModals(){return this.modal.hasOpenModals()}}return e.\u0275fac=function(t){return new(t||e)(i.dc(r.o))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},JP8w:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("8Y7J"),r=n("G0yt");let s=(()=>{class e{constructor(e){this.nav=e,this.localStorage=window.localStorage}ngOnInit(){const e=this.localStorage.getItem("tabset_"+this.cdStatefulTab);e&&this.nav.select(e)}onNavChange(e){this.cdStatefulTab&&e.nextId&&this.localStorage.setItem("tabset_"+this.cdStatefulTab,e.nextId)}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(r.p,9))},e.\u0275dir=i.Hb({type:e,selectors:[["","cdStatefulTab",""]],hostBindings:function(e,t){1&e&&i.gc("navChange",(function(e){return t.onNavChange(e)}))},inputs:{cdStatefulTab:"cdStatefulTab"}}),e})()},JVSJ:function(e,t,n){!function(e){"use strict";function t(e,t,n){var i=e+" ";switch(n){case"ss":return i+(1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi");case"m":return t?"jedna minuta":"jedne minute";case"mm":return i+(1===e?"minuta":2===e||3===e||4===e?"minute":"minuta");case"h":return t?"jedan sat":"jednog sata";case"hh":return i+(1===e?"sat":2===e||3===e||4===e?"sata":"sati");case"dd":return i+(1===e?"dan":"dana");case"MM":return i+(1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci");case"yy":return i+(1===e?"godina":2===e||3===e||4===e?"godine":"godina")}}e.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_\u010detvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._\u010det._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_\u010de_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[ju\u010der u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[pro\u0161lu] dddd [u] LT";case 6:return"[pro\u0161le] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[pro\u0161li] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:t,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(n("wd/R"))},JX91:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("GyhO"),r=n("z+Ro");function s(...e){const t=e[e.length-1];return Object(r.a)(t)?(e.pop(),n=>Object(i.a)(e,n,t)):t=>Object(i.a)(e,t)}},Js68:function(e,t,n){"use strict";t.a=function(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=9007199254740991}},"Ju5/":function(e,t,n){"use strict";var i=n("XqMk"),r="object"==typeof self&&self&&self.Object===Object&&self,s=i.a||r||Function("return this")();t.a=s},JvlW:function(e,t,n){!function(e){"use strict";var t={ss:"sekund\u0117_sekund\u017ei\u0173_sekundes",m:"minut\u0117_minut\u0117s_minut\u0119",mm:"minut\u0117s_minu\u010di\u0173_minutes",h:"valanda_valandos_valand\u0105",hh:"valandos_valand\u0173_valandas",d:"diena_dienos_dien\u0105",dd:"dienos_dien\u0173_dienas",M:"m\u0117nuo_m\u0117nesio_m\u0117nes\u012f",MM:"m\u0117nesiai_m\u0117nesi\u0173_m\u0117nesius",y:"metai_met\u0173_metus",yy:"metai_met\u0173_metus"};function n(e,t,n,i){return t?r(n)[0]:i?r(n)[1]:r(n)[2]}function i(e){return e%10==0||e>10&&e<20}function r(e){return t[e].split("_")}function s(e,t,s,o){var a=e+" ";return 1===e?a+n(0,t,s[0],o):t?a+(i(e)?r(s)[1]:r(s)[0]):o?a+r(s)[1]:a+(i(e)?r(s)[1]:r(s)[2])}e.defineLocale("lt",{months:{format:"sausio_vasario_kovo_baland\u017eio_gegu\u017e\u0117s_bir\u017eelio_liepos_rugpj\u016b\u010dio_rugs\u0117jo_spalio_lapkri\u010dio_gruod\u017eio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegu\u017e\u0117_bir\u017eelis_liepa_rugpj\u016btis_rugs\u0117jis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadien\u012f_pirmadien\u012f_antradien\u012f_tre\u010diadien\u012f_ketvirtadien\u012f_penktadien\u012f_\u0161e\u0161tadien\u012f".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_tre\u010diadienis_ketvirtadienis_penktadienis_\u0161e\u0161tadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_\u0160e\u0161".split("_"),weekdaysMin:"S_P_A_T_K_Pn_\u0160".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[\u0160iandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Pra\u0117jus\u012f] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prie\u0161 %s",s:function(e,t,n,i){return t?"kelios sekund\u0117s":i?"keli\u0173 sekund\u017ei\u0173":"kelias sekundes"},ss:s,m:n,mm:s,h:n,hh:s,d:n,dd:s,M:n,MM:s,y:n,yy:s},dayOfMonthOrdinalParse:/\d{1,2}-oji/,ordinal:function(e){return e+"-oji"},week:{dow:1,doy:4}})}(n("wd/R"))},"K/tc":function(e,t,n){!function(e){"use strict";e.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(e){return/^nm$/i.test(e)},meridiem:function(e,t,n){return e<12?n?"vm":"VM":n?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[M\xf4re om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",ss:"%d sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(n("wd/R"))},KSF8:function(e,t,n){!function(e){"use strict";e.defineLocale("vi",{months:"th\xe1ng 1_th\xe1ng 2_th\xe1ng 3_th\xe1ng 4_th\xe1ng 5_th\xe1ng 6_th\xe1ng 7_th\xe1ng 8_th\xe1ng 9_th\xe1ng 10_th\xe1ng 11_th\xe1ng 12".split("_"),monthsShort:"Thg 01_Thg 02_Thg 03_Thg 04_Thg 05_Thg 06_Thg 07_Thg 08_Thg 09_Thg 10_Thg 11_Thg 12".split("_"),monthsParseExact:!0,weekdays:"ch\u1ee7 nh\u1eadt_th\u1ee9 hai_th\u1ee9 ba_th\u1ee9 t\u01b0_th\u1ee9 n\u0103m_th\u1ee9 s\xe1u_th\u1ee9 b\u1ea3y".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(e){return/^ch$/i.test(e)},meridiem:function(e,t,n){return e<12?n?"sa":"SA":n?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [n\u0103m] YYYY",LLL:"D MMMM [n\u0103m] YYYY HH:mm",LLLL:"dddd, D MMMM [n\u0103m] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[H\xf4m nay l\xfac] LT",nextDay:"[Ng\xe0y mai l\xfac] LT",nextWeek:"dddd [tu\u1ea7n t\u1edbi l\xfac] LT",lastDay:"[H\xf4m qua l\xfac] LT",lastWeek:"dddd [tu\u1ea7n tr\u01b0\u1edbc l\xfac] LT",sameElse:"L"},relativeTime:{future:"%s t\u1edbi",past:"%s tr\u01b0\u1edbc",s:"v\xe0i gi\xe2y",ss:"%d gi\xe2y",m:"m\u1ed9t ph\xfat",mm:"%d ph\xfat",h:"m\u1ed9t gi\u1edd",hh:"%d gi\u1edd",d:"m\u1ed9t ng\xe0y",dd:"%d ng\xe0y",w:"m\u1ed9t tu\u1ea7n",ww:"%d tu\u1ea7n",M:"m\u1ed9t th\xe1ng",MM:"%d th\xe1ng",y:"m\u1ed9t n\u0103m",yy:"%d n\u0103m"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(n("wd/R"))},KTz0:function(e,t,n){!function(e){"use strict";var t={words:{ss:["sekund","sekunda","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,t){return 1===e?t[0]:e>=2&&e<=4?t[1]:t[2]},translate:function(e,n,i){var r=t.words[i];return 1===i.length?n?r[0]:r[1]:e+" "+t.correctGrammaticalCase(e,r)}};e.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_\u010detvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._\u010det._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_\u010de_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[ju\u010de u] LT",lastWeek:function(){return["[pro\u0161le] [nedjelje] [u] LT","[pro\u0161log] [ponedjeljka] [u] LT","[pro\u0161log] [utorka] [u] LT","[pro\u0161le] [srijede] [u] LT","[pro\u0161log] [\u010detvrtka] [u] LT","[pro\u0161log] [petka] [u] LT","[pro\u0161le] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:"dan",dd:t.translate,M:"mjesec",MM:t.translate,y:"godinu",yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(n("wd/R"))},KmKo:function(e,t,n){var i=n("glrk");e.exports=function(e){var t=e.return;if(void 0!==t)return i(t.call(e)).value}},Kqap:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("7o/Q");function r(e,t){let n=!1;return arguments.length>=2&&(n=!0),function(i){return i.lift(new s(e,t,n))}}class s{constructor(e,t,n=!1){this.accumulator=e,this.seed=t,this.hasSeed=n}call(e,t){return t.subscribe(new o(e,this.accumulator,this.seed,this.hasSeed))}}class o extends i.a{constructor(e,t,n,i){super(e),this.accumulator=t,this._seed=n,this.hasSeed=i,this.index=0}get seed(){return this._seed}set seed(e){this.hasSeed=!0,this._seed=e}_next(e){if(this.hasSeed)return this._tryNext(e);this.seed=e,this.destination.next(e)}_tryNext(e){const t=this.index++;let n;try{n=this.accumulator(this.seed,e,t)}catch(i){this.destination.error(i)}this.seed=n,this.destination.next(n)}}},KqfI:function(e,t,n){"use strict";function i(){}n.d(t,"a",(function(){return i}))},L3Qv:function(e,t,n){"use strict";t.a=function(){return!1}},LQDL:function(e,t,n){var i,r,s=n("2oRo"),o=n("NC/Y"),a=s.process,c=a&&a.versions,l=c&&c.v8;l?r=(i=l.split("."))[0]<4?1:i[0]+i[1]:o&&(!(i=o.match(/Edge\/(\d+)/))||i[1]>=74)&&(i=o.match(/Chrome\/(\d+)/))&&(r=i[1]),e.exports=r&&+r},LRne:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("z+Ro"),r=n("yCtX"),s=n("jZKg");function o(...e){let t=e[e.length-1];return Object(i.a)(t)?(e.pop(),Object(s.a)(e,t)):Object(r.a)(e)}},LceX:function(e,t,n){"use strict";n.r(t),n.d(t,"AuthModule",(function(){return Qe})),n.d(t,"RoutedAuthModule",(function(){return Ze}));var i=n("SVse"),r=n("s7LF"),s=n("iInd"),o=n("G0yt"),a=n("zWsK"),c=n("sne2"),l=n("PCNd"),u=n("LvDl"),d=n.n(u),h=n("cp0P"),f=n("LRne"),p=n("5+tZ"),m=n("8Y7J"),b=n("IheW");let g=(()=>{class e{constructor(e){this.http=e}list(){return this.http.get("api/role")}delete(e){return this.http.delete("api/role/"+e)}get(e){return this.http.get("api/role/"+e)}create(e){return this.http.post("api/role",e)}clone(e,t){return this.http.post(`api/role/${e}/clone`,{new_name:t})}update(e){return this.http.put("api/role/"+e.name,e)}exists(e){return this.list().pipe(Object(p.a)(t=>{const n=t.some(t=>t.name===e);return Object(f.a)(n)}))}}return e.\u0275fac=function(t){return new(t||e)(m.dc(b.b))},e.\u0275prov=m.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})(),_=(()=>{class e{constructor(e){this.http=e}list(){return this.http.get("ui-api/scope")}}return e.\u0275fac=function(t){return new(t||e)(m.dc(b.b))},e.\u0275prov=m.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})();var y=n("mtw6"),v=n("spCT"),w=n("QFaf"),S=n("1Ni5"),M=n("9nlD"),x=function(e){return e.editing="editing",e}({});class k{}var D=n("zc8c"),T=n("NwgZ"),C=n("ocLN"),O=n("ANnk"),L=n("f69J"),R=n("IZUe"),E=n("uIqm"),A=n("6+kj"),I=n("8xTl");const P=["headerPermissionCheckboxTpl"],j=["cellScopeCheckboxTpl"],N=["cellPermissionCheckboxTpl"];function F(e,t){1&e&&(m.Sb(0,"span",27),m.Wb(1,28),m.Rb())}function Y(e,t){1&e&&(m.Sb(0,"span",27),m.Wb(1,29),m.Rb())}const z=function(e){return{required:e}};function $(e,t){if(1&e){const e=m.Tb();m.Sb(0,"div",4),m.Sb(1,"form",5,6),m.Sb(3,"div",7),m.Sb(4,"div",8),m.Wb(5,9),m.jc(6,"titlecase"),m.jc(7,"upperFirst"),m.Rb(),m.Sb(8,"div",10),m.Sb(9,"div",11),m.Sb(10,"label",12),m.Wb(11,13),m.Rb(),m.Sb(12,"div",14),m.Sb(13,"input",15),m.Yb(14,16),m.Rb(),m.Mc(15,F,2,0,"span",17),m.Mc(16,Y,2,0,"span",17),m.Rb(),m.Rb(),m.Sb(17,"div",11),m.Sb(18,"label",18),m.Wb(19,19),m.Rb(),m.Sb(20,"div",14),m.Sb(21,"input",20),m.Yb(22,21),m.Rb(),m.Rb(),m.Rb(),m.Sb(23,"div",11),m.Sb(24,"label",22),m.Wb(25,23),m.Rb(),m.Sb(26,"div",14),m.Nb(27,"cd-table",24),m.Rb(),m.Rb(),m.Rb(),m.Sb(28,"div",25),m.Sb(29,"cd-form-button-panel",26),m.gc("submitActionEvent",(function(){return m.Dc(e),m.ic().submit()})),m.jc(30,"titlecase"),m.jc(31,"upperFirst"),m.Rb(),m.Rb(),m.Rb(),m.Rb(),m.Rb()}if(2&e){const e=m.Ac(2),t=m.ic();m.yb(1),m.pc("formGroup",t.roleForm),m.yb(6),m.ac(m.kc(6,15,t.action))(m.kc(7,17,t.resource)),m.Xb(5),m.yb(3),m.pc("ngClass",m.uc(23,z,t.mode!==t.roleFormMode.editing)),m.yb(5),m.pc("ngIf",t.roleForm.showError("name",e,"required")),m.yb(1),m.pc("ngIf",t.roleForm.showError("name",e,"notUnique")),m.yb(11),m.pc("data",t.scopes_permissions)("columns",t.columns)("toolHeader",!1)("autoReload",!1)("autoSave",!1)("footer",!1)("limit",0),m.yb(2),m.pc("form",t.roleForm)("submitText",m.kc(30,19,t.action)+" "+m.kc(31,21,t.resource))}}function H(e,t){if(1&e){const e=m.Tb();m.Sb(0,"div",30),m.Sb(1,"input",31),m.gc("change",(function(n){m.Dc(e);const i=t.row,r=t.column;return m.ic().onClickCellCheckbox(i.scope,r.prop,n)})),m.Rb(),m.Sb(2,"label",32),m.Oc(3),m.Rb(),m.Rb()}if(2&e){const e=t.row,n=t.value,i=m.ic();m.yb(1),m.rc("id","scope_",e.scope,""),m.pc("checked",i.isRowChecked(e.scope)),m.yb(1),m.rc("for","scope_",e.scope,""),m.yb(1),m.Pc(n)}}function W(e,t){if(1&e){const e=m.Tb();m.Sb(0,"div",30),m.Sb(1,"input",33),m.gc("change",(function(n){m.Dc(e);const i=t.row,r=t.column;return m.ic().onClickCellCheckbox(i.scope,r.prop,n)})),m.Rb(),m.Nb(2,"label",34),m.Rb()}if(2&e){const e=t.column,n=t.row,i=t.value;m.yb(1),m.pc("checked",i)("id",n.scope+"-"+e.prop),m.yb(1),m.pc("for",n.scope+"-"+e.prop)}}function V(e,t){if(1&e){const e=m.Tb();m.Sb(0,"div",30),m.Sb(1,"input",31),m.gc("change",(function(n){m.Dc(e);const i=t.column;return m.ic().onClickHeaderCheckbox(i.prop,n)})),m.Rb(),m.Sb(2,"label",35),m.Oc(3),m.Rb(),m.Rb()}if(2&e){const e=t.column,n=m.ic();m.yb(1),m.rc("id","header_",e.prop,""),m.pc("checked",n.isHeaderChecked(e.prop)),m.yb(1),m.rc("for","header_",e.prop,""),m.yb(1),m.Pc(e.name)}}let B=(()=>{class e extends v.a{constructor(e,t,n,i,r,s){super(),this.route=e,this.router=t,this.roleService=n,this.scopeService=i,this.notificationService=r,this.actionLabels=s,this.scopes=[],this.scopes_permissions=[],this.roleFormMode=x,this.resource="role",this.createForm(),this.listenToChanges()}createForm(){this.roleForm=new w.a({name:new r.h("",{validators:[r.A.required],asyncValidators:[S.a.unique(this.roleService.exists,this.roleService)]}),description:new r.h(""),scopes_permissions:new r.h({})})}ngOnInit(){this.columns=[{prop:"scope",name:"All",flexGrow:2,cellTemplate:this.cellScopeCheckboxTpl,headerTemplate:this.headerPermissionCheckboxTpl},{prop:"read",name:"Read",flexGrow:1,cellClass:"text-center",cellTemplate:this.cellPermissionCheckboxTpl,headerTemplate:this.headerPermissionCheckboxTpl},{prop:"create",name:"Create",flexGrow:1,cellClass:"text-center",cellTemplate:this.cellPermissionCheckboxTpl,headerTemplate:this.headerPermissionCheckboxTpl},{prop:"update",name:"Update",flexGrow:1,cellClass:"text-center",cellTemplate:this.cellPermissionCheckboxTpl,headerTemplate:this.headerPermissionCheckboxTpl},{prop:"delete",name:"Delete",flexGrow:1,cellClass:"text-center",cellTemplate:this.cellPermissionCheckboxTpl,headerTemplate:this.headerPermissionCheckboxTpl}],this.router.url.startsWith("/user-management/roles/edit")?(this.mode=this.roleFormMode.editing,this.action=this.actionLabels.EDIT):this.action=this.actionLabels.CREATE,this.mode===this.roleFormMode.editing?this.initEdit():this.initCreate()}initCreate(){this.scopeService.list().subscribe(e=>{this.scopes=e,this.roleForm.get("scopes_permissions").setValue({}),this.loadingReady()})}initEdit(){this.roleForm.get("name").disable(),this.route.params.subscribe(e=>{const t=[];t.push(this.scopeService.list()),t.push(this.roleService.get(e.name)),Object(h.a)(t).subscribe(e=>{this.scopes=e[0],["name","description","scopes_permissions"].forEach(t=>this.roleForm.get(t).setValue(e[1][t])),this.loadingReady()})})}listenToChanges(){this.roleForm.get("scopes_permissions").valueChanges.subscribe(e=>{const t=[];d.a.each(this.scopes,n=>{const i={read:!1,create:!1,update:!1,delete:!1};i.scope=n,n in e&&d.a.each(e[n],e=>{i[e]=!0}),t.push(i)}),this.scopes_permissions=t})}isRowChecked(e){const t=d.a.find(this.scopes_permissions,t=>t.scope===e);return!d.a.isUndefined(t)&&t.read&&t.create&&t.update&&t.delete}isHeaderChecked(e){let t=[e];return"scope"===e&&(t=["read","create","update","delete"]),t.every(e=>this.scopes_permissions.every(t=>t[e]))}onClickCellCheckbox(e,t,n=null){const i=d.a.cloneDeep(this.roleForm.getValue("scopes_permissions"));let r=[t];"scope"===t&&(r=["read","create","update","delete"]),e in i||(i[e]=[]),n&&n.target.checked||!d.a.isEqual(r.sort(),d.a.intersection(i[e],r).sort())?i[e]=d.a.union(i[e],r):(i[e]=d.a.difference(i[e],r),d.a.isEmpty(i[e])&&d.a.unset(i,e)),this.roleForm.get("scopes_permissions").setValue(i)}onClickHeaderCheckbox(e,t){const n=d.a.cloneDeep(this.roleForm.getValue("scopes_permissions"));let i=[e];"scope"===e&&(i=["read","create","update","delete"]),d.a.each(i,e=>{d.a.each(this.scopes,i=>{t.target.checked?n[i]=d.a.union(n[i],[e]):(n[i]=d.a.difference(n[i],[e]),d.a.isEmpty(n[i])&&d.a.unset(n,i))})}),this.roleForm.get("scopes_permissions").setValue(n)}getRequest(){const e=new k;return["name","description","scopes_permissions"].forEach(t=>e[t]=this.roleForm.get(t).value),e}createAction(){const e=this.getRequest();this.roleService.create(e).subscribe(()=>{this.notificationService.show(y.a.success,"Created role '" + e.name + "'"),this.router.navigate(["/user-management/roles"])},()=>{this.roleForm.setErrors({cdSubmitButton:!0})})}editAction(){const e=this.getRequest();this.roleService.update(e).subscribe(()=>{this.notificationService.show(y.a.success,"Updated role '" + e.name + "'"),this.router.navigate(["/user-management/roles"])},()=>{this.roleForm.setErrors({cdSubmitButton:!0})})}submit(){this.mode===this.roleFormMode.editing?this.editAction():this.createAction()}}return e.\u0275fac=function(t){return new(t||e)(m.Mb(s.a),m.Mb(s.e),m.Mb(g),m.Mb(_),m.Mb(M.a),m.Mb(c.b))},e.\u0275cmp=m.Gb({type:e,selectors:[["cd-role-form"]],viewQuery:function(e,t){var n;1&e&&(m.Jc(P,!0),m.Jc(j,!0),m.Jc(N,!0)),2&e&&(m.zc(n=m.hc())&&(t.headerPermissionCheckboxTpl=n.first),m.zc(n=m.hc())&&(t.cellScopeCheckboxTpl=n.first),m.zc(n=m.hc())&&(t.cellPermissionCheckboxTpl=n.first))},features:[m.vb],decls:7,vars:1,consts:function(){return[["class","cd-col-form",4,"cdFormLoading"],["cellScopeCheckboxTpl",""],["cellPermissionCheckboxTpl",""],["headerPermissionCheckboxTpl",""],[1,"cd-col-form"],["name","roleForm","novalidate","",3,"formGroup"],["formDir","ngForm"],[1,"card"],[1,"card-header"],"" + "\ufffd0\ufffd" + " " + "\ufffd1\ufffd" + "",[1,"card-body"],[1,"form-group","row"],["for","name",1,"cd-col-form-label",3,"ngClass"],"Name",[1,"cd-col-form-input"],["type","text","id","name","name","name","formControlName","name","autofocus","",1,"form-control",6,"placeholder"],["placeholder","Name..."],["class","invalid-feedback",4,"ngIf"],["for","description",1,"cd-col-form-label"],"Description",["type","text","id","description","name","description","formControlName","description",1,"form-control",6,"placeholder"],["placeholder","Description..."],[1,"cd-col-form-label"],"Permissions",["columnMode","flex",3,"data","columns","toolHeader","autoReload","autoSave","footer","limit"],[1,"card-footer"],["wrappingClass","text-right",3,"form","submitText","submitActionEvent"],[1,"invalid-feedback"],"This field is required.","The chosen name is already in use.",[1,"custom-control","custom-checkbox"],["type","checkbox",1,"custom-control-input",3,"id","checked","change"],[1,"datatable-permissions-scope-cell-label","custom-control-label",3,"for"],["type","checkbox",1,"custom-control-input",3,"checked","id","change"],[1,"custom-control-label",3,"for"],[1,"datatable-permissions-header-cell-label","custom-control-label",3,"for"]]},template:function(e,t){1&e&&(m.Mc(0,$,32,25,"div",0),m.Mc(1,H,4,4,"ng-template",null,1,m.Nc),m.Mc(3,W,3,3,"ng-template",null,2,m.Nc),m.Mc(5,V,4,4,"ng-template",null,3,m.Nc)),2&e&&m.pc("cdFormLoading",t.loading)},directives:[D.a,r.C,r.r,r.k,T.a,C.a,i.p,O.a,r.d,L.a,r.q,r.i,R.a,i.r,E.a,A.a],pipes:[i.A,I.a],styles:[".datatable-permissions-header-cell-label[_ngcontent-%COMP%], .datatable-permissions-scope-cell-label[_ngcontent-%COMP%]{font-weight:700}"]}),e})();var U=n("+fVR"),q=n("0+/T"),G=n("Rf2I"),J=n("x38r"),Q=n("oxzT"),K=n("vCyI"),Z=n("nSDx"),X=n("aexS"),ee=n("JK/P"),te=n("EgGo");let ne=(()=>{class e{constructor(e){this.router=e}}return e.\u0275fac=function(t){return new(t||e)(m.Mb(s.e))},e.\u0275cmp=m.Gb({type:e,selectors:[["cd-user-tabs"]],decls:8,vars:1,consts:function(){return[["ngbNav","",1,"nav-tabs",3,"activeId","navChange"],["nav","ngbNav"],["ngbNavItem","/user-management/users"],["ngbNavLink",""],"Users",["ngbNavItem","/user-management/roles"],"Roles"]},template:function(e,t){1&e&&(m.Sb(0,"ul",0,1),m.gc("navChange",(function(e){return t.router.navigate([e.nextId])})),m.Sb(2,"li",2),m.Sb(3,"a",3),m.Wb(4,4),m.Rb(),m.Rb(),m.Sb(5,"li",5),m.Sb(6,"a",3),m.Wb(7,6),m.Rb(),m.Rb(),m.Rb()),2&e&&m.pc("activeId",t.router.url)},directives:[o.p,o.r,o.s],styles:[""]}),e})();var ie=n("S7zO");function re(e,t){if(1&e&&(m.Qb(0),m.Nb(1,"cd-table",1),m.Pb()),2&e){const e=m.ic();m.yb(1),m.pc("data",e.scopes_permissions)("columns",e.columns)("toolHeader",!1)("autoReload",!1)("autoSave",!1)("footer",!1)("limit",0)}}let se=(()=>{class e{constructor(){this.scopes_permissions=[]}ngOnInit(){this.columns=[{prop:"scope",name:"Scope",flexGrow:2},{prop:"read",name:"Read",flexGrow:1,cellClass:"text-center",cellTransformation:J.a.checkIcon},{prop:"create",name:"Create",flexGrow:1,cellClass:"text-center",cellTransformation:J.a.checkIcon},{prop:"update",name:"Update",flexGrow:1,cellClass:"text-center",cellTransformation:J.a.checkIcon},{prop:"delete",name:"Delete",flexGrow:1,cellClass:"text-center",cellTransformation:J.a.checkIcon}]}ngOnChanges(){if(this.selection){this.selectedItem=this.selection;const e=[];d.a.each(this.scopes,t=>{const n={read:!1,create:!1,update:!1,delete:!1};n.scope=t,t in this.selectedItem.scopes_permissions&&d.a.each(this.selectedItem.scopes_permissions[t],e=>{n[e]=!0}),e.push(n)}),this.scopes_permissions=e}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=m.Gb({type:e,selectors:[["cd-role-details"]],inputs:{selection:"selection",scopes:"scopes"},features:[m.wb],decls:1,vars:1,consts:[[4,"ngIf"],["columnMode","flex",3,"data","columns","toolHeader","autoReload","autoSave","footer","limit"]],template:function(e,t){1&e&&m.Mc(0,re,2,7,"ng-container",0),2&e&&m.pc("ngIf",t.selection)},directives:[i.r,E.a],styles:[".fa[_ngcontent-%COMP%]{font-size:large}.fa.fa-square-o[_ngcontent-%COMP%]{color:#ced4da}"]}),e})(),oe=(()=>{class e extends U.a{constructor(e,t,n,i,r,s,o,a){super(),this.roleService=e,this.scopeService=t,this.emptyPipe=n,this.authStorageService=i,this.modalService=r,this.notificationService=s,this.urlBuilder=o,this.actionLabels=a,this.selection=new K.a,this.permission=this.authStorageService.getPermissions().user,this.tableActions=[{permission:"create",icon:Q.a.add,routerLink:()=>this.urlBuilder.getCreate(),name:this.actionLabels.CREATE},{permission:"create",icon:Q.a.clone,name:this.actionLabels.CLONE,disable:()=>!this.selection.hasSingleSelection,click:()=>this.cloneRole()},{permission:"update",icon:Q.a.edit,disable:()=>!this.selection.hasSingleSelection||this.selection.first().system,routerLink:()=>this.selection.first()&&this.urlBuilder.getEdit(this.selection.first().name),name:this.actionLabels.EDIT},{permission:"delete",icon:Q.a.destroy,disable:()=>!this.selection.hasSingleSelection||this.selection.first().system,click:()=>this.deleteRoleModal(),name:this.actionLabels.DELETE}]}ngOnInit(){this.columns=[{name:"Name",prop:"name",flexGrow:3},{name:"Description",prop:"description",flexGrow:5,pipe:this.emptyPipe},{name:"System Role",prop:"system",cellClass:"text-center",flexGrow:1,cellTransformation:J.a.checkIcon}]}getRoles(){Object(h.a)([this.roleService.list(),this.scopeService.list()]).subscribe(e=>{this.roles=e[0],this.scopes=e[1]})}updateSelection(e){this.selection=e}deleteRole(e){this.roleService.delete(e).subscribe(()=>{this.getRoles(),this.modalRef.close(),this.notificationService.show(y.a.success,"Deleted role '" + e + "'")},()=>{this.modalRef.componentInstance.stopLoadingSpinner()})}deleteRoleModal(){const e=this.selection.first().name;this.modalRef=this.modalService.show(q.a,{itemDescription:"Role",itemNames:[e],submitAction:()=>this.deleteRole(e)})}cloneRole(){const e=this.selection.first().name;this.modalRef=this.modalService.show(G.a,{fields:[{type:"text",name:"newName",value:e+"_clone",label:"New name",required:!0}],titleText:"Clone Role",submitButtonText:"Clone Role",onSubmit:t=>{this.roleService.clone(e,t.newName).subscribe(()=>{this.getRoles(),this.notificationService.show(y.a.success,"Cloned role '" + t.newName + "' from '" + e + "'")})}})}}return e.\u0275fac=function(t){return new(t||e)(m.Mb(g),m.Mb(_),m.Mb(Z.a),m.Mb(X.a),m.Mb(ee.a),m.Mb(M.a),m.Mb(te.a),m.Mb(c.b))},e.\u0275cmp=m.Gb({type:e,selectors:[["cd-role-list"]],features:[m.xb([{provide:te.a,useValue:new te.a("user-management/roles")}]),m.vb],decls:4,vars:8,consts:[["columnMode","flex","identifier","name","selectionType","single",3,"data","columns","hasDetails","setExpandedRow","fetchData","updateSelection"],[1,"table-actions",3,"permission","selection","tableActions"],["cdTableDetail","",3,"selection","scopes"]],template:function(e,t){1&e&&(m.Nb(0,"cd-user-tabs"),m.Sb(1,"cd-table",0),m.gc("setExpandedRow",(function(e){return t.setExpandedRow(e)}))("fetchData",(function(){return t.getRoles()}))("updateSelection",(function(e){return t.updateSelection(e)})),m.Nb(2,"cd-table-actions",1),m.Nb(3,"cd-role-details",2),m.Rb()),2&e&&(m.yb(1),m.pc("data",t.roles)("columns",t.columns)("hasDetails",!0),m.yb(1),m.pc("permission",t.permission)("selection",t.selection)("tableActions",t.tableActions),m.yb(1),m.pc("selection",t.expandedRow)("scopes",t.scopes))},directives:[ne,E.a,ie.a,se],styles:[""]}),e})();var ae=n("wd/R"),ce=n.n(ae),le=n("DSvg"),ue=n("20UP"),de=n("Mxhz"),he=n("OLbh"),fe=n("DNAf"),pe=n("2EZI"),me=n("oMSZ"),be=n("1nQr"),ge=function(e){return e.editing="editing",e}({});class _e{}var ye=n("D4zM"),ve=n("p4Cf"),we=n("ppaS"),Se=n("MAOJ");const Me=["removeSelfUserReadUpdatePermissionTpl"];function xe(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,29),m.Rb())}function ke(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,30),m.Rb())}function De(e,t){if(1&e&&m.Nb(0,"cd-helper",40),2&e){const e=m.ic(3);m.qc("html",e.passwordPolicyHelpText)}}function Te(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,41),m.Rb())}function Ce(e,t){if(1&e&&(m.Sb(0,"span",28),m.Oc(1),m.Rb()),2&e){const e=m.ic(3);m.yb(1),m.Qc(" ",e.passwordValuation," ")}}function Oe(e,t){if(1&e&&(m.Sb(0,"div",10),m.Sb(1,"label",31),m.Qb(2),m.Wb(3,32),m.Pb(),m.Mc(4,De,1,1,"cd-helper",33),m.Rb(),m.Sb(5,"div",13),m.Sb(6,"div",34),m.Nb(7,"input",35),m.Sb(8,"span",36),m.Nb(9,"button",37),m.Rb(),m.Rb(),m.Sb(10,"div",38),m.Nb(11,"div",39),m.Rb(),m.Mc(12,Te,2,0,"span",15),m.Mc(13,Ce,2,1,"span",15),m.Rb(),m.Rb()),2&e){m.ic();const e=m.Ac(2),t=m.ic();m.yb(4),m.pc("ngIf",t.passwordPolicyHelpText.length>0),m.yb(7),m.Ab(t.passwordStrengthLevelClass),m.qc("title",t.passwordValuation),m.yb(1),m.pc("ngIf",t.userForm.showError("password",e,"required")),m.yb(1),m.pc("ngIf",t.userForm.showError("password",e,"passwordPolicy"))}}function Le(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,46),m.Rb())}function Re(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,47),m.Rb())}function Ee(e,t){if(1&e&&(m.Sb(0,"div",10),m.Sb(1,"label",42),m.Wb(2,43),m.Rb(),m.Sb(3,"div",13),m.Sb(4,"div",34),m.Nb(5,"input",44),m.Sb(6,"span",36),m.Nb(7,"button",45),m.Rb(),m.Mc(8,Le,2,0,"span",15),m.Rb(),m.Mc(9,Re,2,0,"span",15),m.Rb(),m.Rb()),2&e){m.ic();const e=m.Ac(2),t=m.ic();m.yb(8),m.pc("ngIf",t.userForm.showError("confirmpassword",e,"match")),m.yb(1),m.pc("ngIf",t.userForm.showError("confirmpassword",e,"required"))}}function Ae(e,t){1&e&&(m.Sb(0,"cd-helper",55),m.Sb(1,"p"),m.Oc(2," The Dashboard setting defining the expiration interval of passwords is currently set to "),m.Sb(3,"strong"),m.Oc(4,"0"),m.Rb(),m.Oc(5,". This means if a date is set, the user password will only expire once. "),m.Rb(),m.Sb(6,"p"),m.Oc(7," Consider configuring the Dashboard setting "),m.Sb(8,"a",56),m.Oc(9,"USER_PWD_EXPIRATION_SPAN"),m.Rb(),m.Oc(10," in order to let passwords expire periodically. "),m.Rb(),m.Rb())}function Ie(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,57),m.Rb())}const Pe=function(e){return{required:e}};function je(e,t){if(1&e){const e=m.Tb();m.Sb(0,"div",10),m.Sb(1,"label",48),m.Qb(2),m.Wb(3,49),m.Pb(),m.Mc(4,Ae,11,0,"cd-helper",50),m.Rb(),m.Sb(5,"div",13),m.Sb(6,"div",34),m.Sb(7,"input",51,52),m.Yb(9,53),m.gc("click",(function(){return m.Dc(e),m.Ac(8).open()}))("keypress",(function(){return m.Dc(e),m.Ac(8).close()})),m.Rb(),m.Sb(10,"span",36),m.Sb(11,"button",54),m.gc("click",(function(){return m.Dc(e),m.ic(2).clearExpirationDate()})),m.Nb(12,"i"),m.Rb(),m.Rb(),m.Mc(13,Ie,2,0,"span",15),m.Rb(),m.Rb(),m.Rb()}if(2&e){m.ic();const e=m.Ac(2),t=m.ic(),n=m.Ac(4);m.yb(1),m.pc("ngClass",m.uc(7,Pe,t.pwdExpirationSettings.pwdExpirationSpan>0)),m.yb(3),m.pc("ngIf",0==t.pwdExpirationSettings.pwdExpirationSpan),m.yb(3),m.pc("ngbPopover",n),m.yb(5),m.Bb("icon-prepend ",t.icons.destroy,""),m.yb(1),m.pc("ngIf",t.userForm.showError("pwdExpirationDate",e,"required"))}}function Ne(e,t){1&e&&(m.Sb(0,"span",28),m.Wb(1,58),m.Rb())}function Fe(e,t){if(1&e&&(m.Sb(0,"span",59),m.Nb(1,"cd-select-badges",60),m.Rb()),2&e){const e=m.ic(2);m.yb(1),m.pc("data",e.userForm.controls.roles.value)("options",e.allRoles)("messages",e.messages)}}function Ye(e,t){1&e&&(m.Sb(0,"div",10),m.Sb(1,"div",61),m.Sb(2,"div",62),m.Nb(3,"input",63),m.Sb(4,"label",64),m.Wb(5,65),m.Rb(),m.Rb(),m.Rb(),m.Rb())}function ze(e,t){1&e&&(m.Sb(0,"div",10),m.Sb(1,"div",61),m.Sb(2,"div",62),m.Nb(3,"input",66),m.Sb(4,"label",67),m.Wb(5,68),m.Rb(),m.Rb(),m.Rb(),m.Rb())}function $e(e,t){if(1&e){const e=m.Tb();m.Sb(0,"div",3),m.Sb(1,"form",4,5),m.Sb(3,"div",6),m.Sb(4,"div",7),m.Wb(5,8),m.jc(6,"titlecase"),m.jc(7,"upperFirst"),m.Rb(),m.Sb(8,"div",9),m.Sb(9,"div",10),m.Sb(10,"label",11),m.Wb(11,12),m.Rb(),m.Sb(12,"div",13),m.Nb(13,"input",14),m.Mc(14,xe,2,0,"span",15),m.Mc(15,ke,2,0,"span",15),m.Rb(),m.Rb(),m.Mc(16,Oe,14,7,"div",16),m.Mc(17,Ee,10,2,"div",16),m.Mc(18,je,14,9,"div",16),m.Sb(19,"div",10),m.Sb(20,"label",17),m.Wb(21,18),m.Rb(),m.Sb(22,"div",13),m.Nb(23,"input",19),m.Rb(),m.Rb(),m.Sb(24,"div",10),m.Sb(25,"label",20),m.Wb(26,21),m.Rb(),m.Sb(27,"div",13),m.Nb(28,"input",22),m.Mc(29,Ne,2,0,"span",15),m.Rb(),m.Rb(),m.Sb(30,"div",10),m.Sb(31,"label",23),m.Wb(32,24),m.Rb(),m.Sb(33,"div",13),m.Mc(34,Fe,2,3,"span",25),m.Rb(),m.Rb(),m.Mc(35,Ye,6,0,"div",16),m.Mc(36,ze,6,0,"div",16),m.Rb(),m.Sb(37,"div",26),m.Sb(38,"cd-form-button-panel",27),m.gc("submitActionEvent",(function(){return m.Dc(e),m.ic().submit()})),m.jc(39,"titlecase"),m.jc(40,"upperFirst"),m.Rb(),m.Rb(),m.Rb(),m.Rb(),m.Rb()}if(2&e){const e=m.Ac(2),t=m.ic();m.yb(1),m.pc("formGroup",t.userForm),m.yb(6),m.ac(m.kc(6,15,t.action))(m.kc(7,17,t.resource)),m.Xb(5),m.yb(3),m.pc("ngClass",m.uc(23,Pe,t.mode!==t.userFormMode.editing)),m.yb(4),m.pc("ngIf",t.userForm.showError("username",e,"required")),m.yb(1),m.pc("ngIf",t.userForm.showError("username",e,"notUnique")),m.yb(1),m.pc("ngIf",!t.authStorageService.isSSO()),m.yb(1),m.pc("ngIf",!t.authStorageService.isSSO()),m.yb(1),m.pc("ngIf",!t.authStorageService.isSSO()),m.yb(11),m.pc("ngIf",t.userForm.showError("email",e,"email")),m.yb(5),m.pc("ngIf",t.allRoles),m.yb(1),m.pc("ngIf",!t.isCurrentUser()),m.yb(1),m.pc("ngIf",!t.isCurrentUser()&&!t.authStorageService.isSSO()),m.yb(2),m.pc("form",t.userForm)("submitText",m.kc(39,19,t.action)+" "+m.kc(40,21,t.resource))}}function He(e,t){1&e&&(m.Sb(0,"p"),m.Sb(1,"strong"),m.Wb(2,69),m.Rb(),m.Rb(),m.Nb(3,"br"),m.Sb(4,"p"),m.Wb(5,70),m.Rb(),m.Qb(6),m.Wb(7,71),m.Pb())}function We(e,t){if(1&e&&m.Nb(0,"cd-date-time-picker",72),2&e){const e=m.ic();m.pc("control",e.userForm.get("pwdExpirationDate"))("hasTime",!1)}}let Ve=(()=>{class e extends v.a{constructor(e,t,n,i,r,s,o,a,c,l,u,d){super(),this.authService=e,this.authStorageService=t,this.route=n,this.router=i,this.modalService=r,this.roleService=s,this.userService=o,this.notificationService=a,this.actionLabels=c,this.passwordPolicyService=l,this.formBuilder=u,this.settingsService=d,this.userFormMode=ge,this.messages=new fe.a({empty:"There are no roles."}),this.passwordPolicyHelpText="",this.icons=Q.a,this.pwdExpirationFormat="YYYY-MM-DD",this.resource="user",this.createForm(),this.messages=new fe.a({empty:"There are no roles."})}createForm(){this.passwordPolicyService.getHelpText().subscribe(e=>{this.passwordPolicyHelpText=e}),this.userForm=this.formBuilder.group({username:["",[r.A.required],[S.a.unique(this.userService.validateUserName,this.userService)]],name:[""],password:["",[],[S.a.passwordPolicy(this.userService,()=>this.userForm.getValue("username"),(e,t,n)=>{this.passwordStrengthLevelClass=this.passwordPolicyService.mapCreditsToCssClass(t),this.passwordValuation=d.a.defaultTo(n,"")})]],confirmpassword:[""],pwdExpirationDate:[void 0],email:["",[S.a.email]],roles:[[]],enabled:[!0,[r.A.required]],pwdUpdateRequired:[!0]},{validators:[S.a.match("password","confirmpassword")]})}ngOnInit(){this.router.url.startsWith("/user-management/users/edit")?(this.mode=this.userFormMode.editing,this.action=this.actionLabels.EDIT):this.action=this.actionLabels.CREATE;const e=[this.roleService.list(),this.settingsService.getStandardSettings()];Object(h.a)(e).subscribe(e=>{if(this.allRoles=d.a.map(e[0],e=>(e.enabled=!0,e)),this.pwdExpirationSettings=new me.a(e[1]),this.mode===this.userFormMode.editing)this.initEdit();else{if(this.pwdExpirationSettings.pwdExpirationSpan>0){const e=this.userForm.get("pwdExpirationDate"),t=ce()();t.add(this.pwdExpirationSettings.pwdExpirationSpan,"day"),e.setValue(t.format(this.pwdExpirationFormat)),e.setValidators([r.A.required])}this.loadingReady()}})}initEdit(){this.disableForEdit(),this.route.params.subscribe(e=>{this.userService.get(e.username).subscribe(e=>{this.response=d.a.cloneDeep(e),this.setResponse(e),this.loadingReady()})})}disableForEdit(){this.userForm.get("username").disable()}setResponse(e){["username","name","email","roles","enabled","pwdUpdateRequired"].forEach(t=>this.userForm.get(t).setValue(e[t]));const t=e.pwdExpirationDate;t&&this.userForm.get("pwdExpirationDate").setValue(ce()(1e3*t).format(this.pwdExpirationFormat))}getRequest(){const e=new _e;["username","password","name","email","roles","enabled","pwdUpdateRequired"].forEach(t=>e[t]=this.userForm.get(t).value);const t=this.userForm.get("pwdExpirationDate").value;if(t){const n=ce()(t,this.pwdExpirationFormat);this.mode===this.userFormMode.editing&&this.response.pwdExpirationDate===n.unix()||n.set({hour:23,minute:59,second:59}),e.pwdExpirationDate=n.unix()}return e}createAction(){const e=this.getRequest();this.userService.create(e).subscribe(()=>{this.notificationService.show(y.a.success,"Created user '" + e.username + "'"),this.router.navigate(["/user-management/users"])},()=>{this.userForm.setErrors({cdSubmitButton:!0})})}editAction(){if(this.isUserRemovingNeededRolePermissions()){const e={titleText:"Update user",buttonText:"Continue",bodyTpl:this.removeSelfUserReadUpdatePermissionTpl,onSubmit:()=>{this.modalRef.close(),this.doEditAction()},onCancel:()=>{this.userForm.setErrors({cdSubmitButton:!0}),this.userForm.get("roles").reset(this.userForm.get("roles").value)}};this.modalRef=this.modalService.show(he.a,e)}else this.doEditAction()}isCurrentUser(){return this.authStorageService.getUsername()===this.userForm.getValue("username")}isUserChangingRoles(){return this.isCurrentUser()&&this.response&&!d.a.isEqual(this.response.roles,this.userForm.getValue("roles"))}isUserRemovingNeededRolePermissions(){return this.isCurrentUser()&&!this.hasUserReadUpdatePermissions(this.userForm.getValue("roles"))}hasUserReadUpdatePermissions(e=[]){for(const t of this.allRoles)if(-1!==e.indexOf(t.name)&&t.scopes_permissions.user){const e=t.scopes_permissions.user;return["read","update"].every(t=>-1!==e.indexOf(t))}return!1}doEditAction(){const e=this.getRequest();this.userService.update(e).subscribe(()=>{this.isUserChangingRoles()?this.authService.logout(()=>{this.notificationService.show(y.a.info,"You were automatically logged out because your roles have been changed.")}):(this.notificationService.show(y.a.success,"Updated user '" + e.username + "'"),this.router.navigate(["/user-management/users"]))},()=>{this.userForm.setErrors({cdSubmitButton:!0})})}clearExpirationDate(){this.userForm.get("pwdExpirationDate").setValue(void 0)}submit(){this.mode===this.userFormMode.editing?this.editAction():this.createAction()}}return e.\u0275fac=function(t){return new(t||e)(m.Mb(le.a),m.Mb(X.a),m.Mb(s.a),m.Mb(s.e),m.Mb(ee.a),m.Mb(g),m.Mb(de.a),m.Mb(M.a),m.Mb(c.b),m.Mb(be.a),m.Mb(pe.a),m.Mb(ue.a))},e.\u0275cmp=m.Gb({type:e,selectors:[["cd-user-form"]],viewQuery:function(e,t){var n;1&e&&m.Jc(Me,!0),2&e&&m.zc(n=m.hc())&&(t.removeSelfUserReadUpdatePermissionTpl=n.first)},features:[m.vb],decls:5,vars:1,consts:function(){return[["class","cd-col-form",4,"cdFormLoading"],["removeSelfUserReadUpdatePermissionTpl",""],["popContent",""],[1,"cd-col-form"],["name","userForm","novalidate","",3,"formGroup"],["formDir","ngForm"],[1,"card"],[1,"card-header"],"" + "\ufffd0\ufffd" + " " + "\ufffd1\ufffd" + "",[1,"card-body"],[1,"form-group","row"],["for","username",1,"cd-col-form-label",3,"ngClass"],"Username",[1,"cd-col-form-input"],["type","text","placeholder","Username...","id","username","name","username","formControlName","username","autocomplete","off","autofocus","",1,"form-control"],["class","invalid-feedback",4,"ngIf"],["class","form-group row",4,"ngIf"],["for","name",1,"cd-col-form-label"],"Full name",["type","text","placeholder","Full name...","id","name","name","name","formControlName","name",1,"form-control"],["for","email",1,"cd-col-form-label"],"Email",["type","email","placeholder","Email...","id","email","name","email","formControlName","email",1,"form-control"],[1,"cd-col-form-label"],"Roles",["class","no-border full-height",4,"ngIf"],[1,"card-footer"],["wrappingClass","text-right",3,"form","submitText","submitActionEvent"],[1,"invalid-feedback"],"This field is required.","The username already exists.",["for","password",1,"cd-col-form-label"],"Password",["class","text-pre-wrap",3,"html",4,"ngIf"],[1,"input-group"],["type","password","placeholder","Password...","id","password","name","password","autocomplete","new-password","formControlName","password",1,"form-control"],[1,"input-group-append"],["type","button","cdPasswordButton","password",1,"btn","btn-light"],[1,"password-strength-level"],["data-toggle","tooltip",3,"title"],[1,"text-pre-wrap",3,"html"],"This field is required.",["for","confirmpassword",1,"cd-col-form-label"],"Confirm password",["type","password","placeholder","Confirm password...","id","confirmpassword","name","confirmpassword","autocomplete","new-password","formControlName","confirmpassword",1,"form-control"],["type","button","cdPasswordButton","confirmpassword",1,"btn","btn-light"],"Password confirmation doesn't match the password.","This field is required.",["for","pwdExpirationDate",1,"cd-col-form-label",3,"ngClass"],"Password expiration date",["class","text-pre-wrap",4,"ngIf"],["id","pwdExpirationDate","name","pwdExpirationDate","formControlName","pwdExpirationDate","triggers","manual",1,"form-control",3,"ngbPopover","click","keypress",6,"placeholder"],["p","ngbPopover"],["placeholder","Password expiration date..."],["type","button",1,"btn","btn-light",3,"click"],[1,"text-pre-wrap"],["routerLink","/mgr-modules/edit/dashboard",1,"alert-link"],"This field is required.","Invalid email.",[1,"no-border","full-height"],[3,"data","options","messages"],[1,"cd-col-form-offset"],[1,"custom-control","custom-checkbox"],["type","checkbox","id","enabled","name","enabled","formControlName","enabled",1,"custom-control-input"],["for","enabled",1,"custom-control-label"],"Enabled",["type","checkbox","id","pwdUpdateRequired","name","pwdUpdateRequired","formControlName","pwdUpdateRequired",1,"custom-control-input"],["for","pwdUpdateRequired",1,"custom-control-label"],"User must change password at next logon","You are about to remove \"user read / update\" permissions from your own user.","If you continue, you will no longer be able to add or remove roles from any user.","Are you sure you want to continue?",[3,"control","hasTime"]]},template:function(e,t){1&e&&(m.Mc(0,$e,41,25,"div",0),m.Mc(1,He,8,0,"ng-template",null,1,m.Nc),m.Mc(3,We,1,2,"ng-template",null,2,m.Nc)),2&e&&m.pc("cdFormLoading",t.loading)},directives:[D.a,r.C,r.r,r.k,T.a,C.a,i.p,O.a,r.d,L.a,r.q,r.i,R.a,i.r,A.a,ye.a,ve.a,o.w,s.h,we.a,r.b,Se.a],pipes:[i.A,I.a],styles:[""]}),e})();var Be=n("a0VL");const Ue=["userRolesTpl"];function qe(e,t){if(1&e&&(m.Sb(0,"span"),m.Oc(1),m.Rb()),2&e){const e=t.$implicit,n=t.last;m.yb(1),m.Rc(" ",e,"",n?"":", "," ")}}function Ge(e,t){1&e&&m.Mc(0,qe,2,2,"span",3),2&e&&m.pc("ngForOf",t.value)}let Je=(()=>{class e{constructor(e,t,n,i,r,s,o,a){this.userService=e,this.emptyPipe=t,this.modalService=n,this.notificationService=i,this.authStorageService=r,this.urlBuilder=s,this.cdDatePipe=o,this.actionLabels=a,this.selection=new K.a,this.permission=this.authStorageService.getPermissions().user,this.tableActions=[{permission:"create",icon:Q.a.add,routerLink:()=>this.urlBuilder.getCreate(),name:this.actionLabels.CREATE},{permission:"update",icon:Q.a.edit,routerLink:()=>this.selection.first()&&this.urlBuilder.getEdit(this.selection.first().username),name:this.actionLabels.EDIT},{permission:"delete",icon:Q.a.destroy,click:()=>this.deleteUserModal(),name:this.actionLabels.DELETE}]}ngOnInit(){this.columns=[{name:"Username",prop:"username",flexGrow:1},{name:"Name",prop:"name",flexGrow:1,pipe:this.emptyPipe},{name:"Email",prop:"email",flexGrow:1,pipe:this.emptyPipe},{name:"Roles",prop:"roles",flexGrow:1,cellTemplate:this.userRolesTpl},{name:"Enabled",prop:"enabled",flexGrow:1,cellTransformation:J.a.checkIcon},{name:"Password expiration date",prop:"pwdExpirationDate",flexGrow:1,pipe:this.cdDatePipe}]}getUsers(){this.userService.list().subscribe(e=>{e.forEach(e=>{e.pwdExpirationDate&&e.pwdExpirationDate>0&&(e.pwdExpirationDate=1e3*e.pwdExpirationDate)}),this.users=e})}updateSelection(e){this.selection=e}deleteUser(e){this.userService.delete(e).subscribe(()=>{this.getUsers(),this.modalRef.close(),this.notificationService.show(y.a.success,"Deleted user '" + e + "'")},()=>{this.modalRef.componentInstance.stopLoadingSpinner()})}deleteUserModal(){const e=this.authStorageService.getUsername(),t=this.selection.first().username;e!==t?this.modalRef=this.modalService.show(q.a,{itemDescription:"User",itemNames:[t],submitAction:()=>this.deleteUser(t)}):this.notificationService.show(y.a.error,"Failed to delete user '" + t + "'","You are currently logged in as '" + t + "'.")}}return e.\u0275fac=function(t){return new(t||e)(m.Mb(de.a),m.Mb(Z.a),m.Mb(ee.a),m.Mb(M.a),m.Mb(X.a),m.Mb(te.a),m.Mb(Be.a),m.Mb(c.b))},e.\u0275cmp=m.Gb({type:e,selectors:[["cd-user-list"]],viewQuery:function(e,t){var n;1&e&&m.Jc(Ue,!0),2&e&&m.zc(n=m.hc())&&(t.userRolesTpl=n.first)},features:[m.xb([{provide:te.a,useValue:new te.a("user-management/users")}])],decls:5,vars:5,consts:[["columnMode","flex","identifier","username","selectionType","single",3,"data","columns","fetchData","updateSelection"],[1,"table-actions",3,"permission","selection","tableActions"],["userRolesTpl",""],[4,"ngFor","ngForOf"]],template:function(e,t){1&e&&(m.Nb(0,"cd-user-tabs"),m.Sb(1,"cd-table",0),m.gc("fetchData",(function(){return t.getUsers()}))("updateSelection",(function(e){return t.updateSelection(e)})),m.Nb(2,"cd-table-actions",1),m.Rb(),m.Mc(3,Ge,1,1,"ng-template",null,2,m.Nc)),2&e&&(m.yb(1),m.pc("data",t.users)("columns",t.columns),m.yb(1),m.pc("permission",t.permission)("selection",t.selection)("tableActions",t.tableActions))},directives:[ne,E.a,ie.a,i.q],styles:[""]}),e})(),Qe=(()=>{class e{}return e.\u0275mod=m.Kb({type:e}),e.\u0275inj=m.Jb({factory:function(t){return new(t||e)},imports:[[i.c,r.m,r.x,l.a,o.t,o.y,a.a,s.i]]}),e})();const Ke=[{path:"",redirectTo:"users",pathMatch:"full"},{path:"users",data:{breadcrumbs:"Users"},children:[{path:"",component:Je},{path:c.e.CREATE,component:Ve,data:{breadcrumbs:c.a.CREATE}},{path:c.e.EDIT+"/:username",component:Ve,data:{breadcrumbs:c.a.EDIT}}]},{path:"roles",data:{breadcrumbs:"Roles"},children:[{path:"",component:oe},{path:c.e.CREATE,component:B,data:{breadcrumbs:c.a.CREATE}},{path:c.e.EDIT+"/:name",component:B,data:{breadcrumbs:c.a.EDIT}}]}];let Ze=(()=>{class e{}return e.\u0275mod=m.Kb({type:e}),e.\u0275inj=m.Jb({factory:function(t){return new(t||e)},imports:[[Qe,s.i.forChild(Ke)]]}),e})()},Lhse:function(e,t,n){"use strict";function i(){return"function"==typeof Symbol&&Symbol.iterator?Symbol.iterator:"@@iterator"}n.d(t,"a",(function(){return r}));const r=i()},Loxo:function(e,t,n){!function(e){"use strict";e.defineLocale("uz",{months:"\u044f\u043d\u0432\u0430\u0440_\u0444\u0435\u0432\u0440\u0430\u043b_\u043c\u0430\u0440\u0442_\u0430\u043f\u0440\u0435\u043b_\u043c\u0430\u0439_\u0438\u044e\u043d_\u0438\u044e\u043b_\u0430\u0432\u0433\u0443\u0441\u0442_\u0441\u0435\u043d\u0442\u044f\u0431\u0440_\u043e\u043a\u0442\u044f\u0431\u0440_\u043d\u043e\u044f\u0431\u0440_\u0434\u0435\u043a\u0430\u0431\u0440".split("_"),monthsShort:"\u044f\u043d\u0432_\u0444\u0435\u0432_\u043c\u0430\u0440_\u0430\u043f\u0440_\u043c\u0430\u0439_\u0438\u044e\u043d_\u0438\u044e\u043b_\u0430\u0432\u0433_\u0441\u0435\u043d_\u043e\u043a\u0442_\u043d\u043e\u044f_\u0434\u0435\u043a".split("_"),weekdays:"\u042f\u043a\u0448\u0430\u043d\u0431\u0430_\u0414\u0443\u0448\u0430\u043d\u0431\u0430_\u0421\u0435\u0448\u0430\u043d\u0431\u0430_\u0427\u043e\u0440\u0448\u0430\u043d\u0431\u0430_\u041f\u0430\u0439\u0448\u0430\u043d\u0431\u0430_\u0416\u0443\u043c\u0430_\u0428\u0430\u043d\u0431\u0430".split("_"),weekdaysShort:"\u042f\u043a\u0448_\u0414\u0443\u0448_\u0421\u0435\u0448_\u0427\u043e\u0440_\u041f\u0430\u0439_\u0416\u0443\u043c_\u0428\u0430\u043d".split("_"),weekdaysMin:"\u042f\u043a_\u0414\u0443_\u0421\u0435_\u0427\u043e_\u041f\u0430_\u0416\u0443_\u0428\u0430".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[\u0411\u0443\u0433\u0443\u043d \u0441\u043e\u0430\u0442] LT [\u0434\u0430]",nextDay:"[\u042d\u0440\u0442\u0430\u0433\u0430] LT [\u0434\u0430]",nextWeek:"dddd [\u043a\u0443\u043d\u0438 \u0441\u043e\u0430\u0442] LT [\u0434\u0430]",lastDay:"[\u041a\u0435\u0447\u0430 \u0441\u043e\u0430\u0442] LT [\u0434\u0430]",lastWeek:"[\u0423\u0442\u0433\u0430\u043d] dddd [\u043a\u0443\u043d\u0438 \u0441\u043e\u0430\u0442] LT [\u0434\u0430]",sameElse:"L"},relativeTime:{future:"\u042f\u043a\u0438\u043d %s \u0438\u0447\u0438\u0434\u0430",past:"\u0411\u0438\u0440 \u043d\u0435\u0447\u0430 %s \u043e\u043b\u0434\u0438\u043d",s:"\u0444\u0443\u0440\u0441\u0430\u0442",ss:"%d \u0444\u0443\u0440\u0441\u0430\u0442",m:"\u0431\u0438\u0440 \u0434\u0430\u043a\u0438\u043a\u0430",mm:"%d \u0434\u0430\u043a\u0438\u043a\u0430",h:"\u0431\u0438\u0440 \u0441\u043e\u0430\u0442",hh:"%d \u0441\u043e\u0430\u0442",d:"\u0431\u0438\u0440 \u043a\u0443\u043d",dd:"%d \u043a\u0443\u043d",M:"\u0431\u0438\u0440 \u043e\u0439",MM:"%d \u043e\u0439",y:"\u0431\u0438\u0440 \u0439\u0438\u043b",yy:"%d \u0439\u0438\u043b"},week:{dow:1,doy:7}})}(n("wd/R"))},LvDl:function(e,t,n){(function(e){var i;(function(){var r,s="Expected a function",o="__lodash_hash_undefined__",a="__lodash_placeholder__",c=32,l=128,u=1/0,d=9007199254740991,h=NaN,f=4294967295,p=[["ary",l],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",c],["partialRight",64],["rearg",256]],m="[object Arguments]",b="[object Array]",g="[object Boolean]",_="[object Date]",y="[object Error]",v="[object Function]",w="[object GeneratorFunction]",S="[object Map]",M="[object Number]",x="[object Object]",k="[object Promise]",D="[object RegExp]",T="[object Set]",C="[object String]",O="[object Symbol]",L="[object WeakMap]",R="[object ArrayBuffer]",E="[object DataView]",A="[object Float32Array]",I="[object Float64Array]",P="[object Int8Array]",j="[object Int16Array]",N="[object Int32Array]",F="[object Uint8Array]",Y="[object Uint8ClampedArray]",z="[object Uint16Array]",$="[object Uint32Array]",H=/\b__p \+= '';/g,W=/\b(__p \+=) '' \+/g,V=/(__e\(.*?\)|\b__t\)) \+\n'';/g,B=/&(?:amp|lt|gt|quot|#39);/g,U=/[&<>"']/g,q=RegExp(B.source),G=RegExp(U.source),J=/<%-([\s\S]+?)%>/g,Q=/<%([\s\S]+?)%>/g,K=/<%=([\s\S]+?)%>/g,Z=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,X=/^\w*$/,ee=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,te=/[\\^$.*+?()[\]{}|]/g,ne=RegExp(te.source),ie=/^\s+/,re=/\s/,se=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,oe=/\{\n\/\* \[wrapped with (.+)\] \*/,ae=/,? & /,ce=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g,le=/[()=,{}\[\]\/\s]/,ue=/\\(\\)?/g,de=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,he=/\w*$/,fe=/^[-+]0x[0-9a-f]+$/i,pe=/^0b[01]+$/i,me=/^\[object .+?Constructor\]$/,be=/^0o[0-7]+$/i,ge=/^(?:0|[1-9]\d*)$/,_e=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,ye=/($^)/,ve=/['\n\r\u2028\u2029\\]/g,we="\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff",Se="a-z\\xdf-\\xf6\\xf8-\\xff",Me="A-Z\\xc0-\\xd6\\xd8-\\xde",xe="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",ke="["+xe+"]",De="["+we+"]",Te="\\d+",Ce="["+Se+"]",Oe="[^\\ud800-\\udfff"+xe+Te+"\\u2700-\\u27bf"+Se+Me+"]",Le="\\ud83c[\\udffb-\\udfff]",Re="[^\\ud800-\\udfff]",Ee="(?:\\ud83c[\\udde6-\\uddff]){2}",Ae="[\\ud800-\\udbff][\\udc00-\\udfff]",Ie="["+Me+"]",Pe="(?:"+Ce+"|"+Oe+")",je="(?:"+Ie+"|"+Oe+")",Ne="(?:['\u2019](?:d|ll|m|re|s|t|ve))?",Fe="(?:['\u2019](?:D|LL|M|RE|S|T|VE))?",Ye="(?:"+De+"|"+Le+")?",ze="[\\ufe0e\\ufe0f]?",$e=ze+Ye+"(?:\\u200d(?:"+[Re,Ee,Ae].join("|")+")"+ze+Ye+")*",He="(?:"+["[\\u2700-\\u27bf]",Ee,Ae].join("|")+")"+$e,We="(?:"+[Re+De+"?",De,Ee,Ae,"[\\ud800-\\udfff]"].join("|")+")",Ve=RegExp("['\u2019]","g"),Be=RegExp(De,"g"),Ue=RegExp(Le+"(?="+Le+")|"+We+$e,"g"),qe=RegExp([Ie+"?"+Ce+"+"+Ne+"(?="+[ke,Ie,"$"].join("|")+")",je+"+"+Fe+"(?="+[ke,Ie+Pe,"$"].join("|")+")",Ie+"?"+Pe+"+"+Ne,Ie+"+"+Fe,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",Te,He].join("|"),"g"),Ge=RegExp("[\\u200d\\ud800-\\udfff"+we+"\\ufe0e\\ufe0f]"),Je=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/,Qe=["Array","Buffer","DataView","Date","Error","Float32Array","Float64Array","Function","Int8Array","Int16Array","Int32Array","Map","Math","Object","Promise","RegExp","Set","String","Symbol","TypeError","Uint8Array","Uint8ClampedArray","Uint16Array","Uint32Array","WeakMap","_","clearTimeout","isFinite","parseInt","setTimeout"],Ke=-1,Ze={};Ze[A]=Ze[I]=Ze[P]=Ze[j]=Ze[N]=Ze[F]=Ze[Y]=Ze[z]=Ze[$]=!0,Ze[m]=Ze[b]=Ze[R]=Ze[g]=Ze[E]=Ze[_]=Ze[y]=Ze[v]=Ze[S]=Ze[M]=Ze[x]=Ze[D]=Ze[T]=Ze[C]=Ze[L]=!1;var Xe={};Xe[m]=Xe[b]=Xe[R]=Xe[E]=Xe[g]=Xe[_]=Xe[A]=Xe[I]=Xe[P]=Xe[j]=Xe[N]=Xe[S]=Xe[M]=Xe[x]=Xe[D]=Xe[T]=Xe[C]=Xe[O]=Xe[F]=Xe[Y]=Xe[z]=Xe[$]=!0,Xe[y]=Xe[v]=Xe[L]=!1;var et={"\\":"\\","'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},tt=parseFloat,nt=parseInt,it="object"==typeof global&&global&&global.Object===Object&&global,rt="object"==typeof self&&self&&self.Object===Object&&self,st=it||rt||Function("return this")(),ot=t&&!t.nodeType&&t,at=ot&&"object"==typeof e&&e&&!e.nodeType&&e,ct=at&&at.exports===ot,lt=ct&&it.process,ut=function(){try{return at&&at.require&&at.require("util").types||lt&<.binding&<.binding("util")}catch(e){}}(),dt=ut&&ut.isArrayBuffer,ht=ut&&ut.isDate,ft=ut&&ut.isMap,pt=ut&&ut.isRegExp,mt=ut&&ut.isSet,bt=ut&&ut.isTypedArray;function gt(e,t,n){switch(n.length){case 0:return e.call(t);case 1:return e.call(t,n[0]);case 2:return e.call(t,n[0],n[1]);case 3:return e.call(t,n[0],n[1],n[2])}return e.apply(t,n)}function _t(e,t,n,i){for(var r=-1,s=null==e?0:e.length;++r-1}function xt(e,t,n){for(var i=-1,r=null==e?0:e.length;++i-1;);return n}function qt(e,t){for(var n=e.length;n--&&At(t,e[n],0)>-1;);return n}function Gt(e,t){for(var n=e.length,i=0;n--;)e[n]===t&&++i;return i}var Jt=Ft({"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a","\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y","\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss","\u0100":"A","\u0102":"A","\u0104":"A","\u0101":"a","\u0103":"a","\u0105":"a","\u0106":"C","\u0108":"C","\u010a":"C","\u010c":"C","\u0107":"c","\u0109":"c","\u010b":"c","\u010d":"c","\u010e":"D","\u0110":"D","\u010f":"d","\u0111":"d","\u0112":"E","\u0114":"E","\u0116":"E","\u0118":"E","\u011a":"E","\u0113":"e","\u0115":"e","\u0117":"e","\u0119":"e","\u011b":"e","\u011c":"G","\u011e":"G","\u0120":"G","\u0122":"G","\u011d":"g","\u011f":"g","\u0121":"g","\u0123":"g","\u0124":"H","\u0126":"H","\u0125":"h","\u0127":"h","\u0128":"I","\u012a":"I","\u012c":"I","\u012e":"I","\u0130":"I","\u0129":"i","\u012b":"i","\u012d":"i","\u012f":"i","\u0131":"i","\u0134":"J","\u0135":"j","\u0136":"K","\u0137":"k","\u0138":"k","\u0139":"L","\u013b":"L","\u013d":"L","\u013f":"L","\u0141":"L","\u013a":"l","\u013c":"l","\u013e":"l","\u0140":"l","\u0142":"l","\u0143":"N","\u0145":"N","\u0147":"N","\u014a":"N","\u0144":"n","\u0146":"n","\u0148":"n","\u014b":"n","\u014c":"O","\u014e":"O","\u0150":"O","\u014d":"o","\u014f":"o","\u0151":"o","\u0154":"R","\u0156":"R","\u0158":"R","\u0155":"r","\u0157":"r","\u0159":"r","\u015a":"S","\u015c":"S","\u015e":"S","\u0160":"S","\u015b":"s","\u015d":"s","\u015f":"s","\u0161":"s","\u0162":"T","\u0164":"T","\u0166":"T","\u0163":"t","\u0165":"t","\u0167":"t","\u0168":"U","\u016a":"U","\u016c":"U","\u016e":"U","\u0170":"U","\u0172":"U","\u0169":"u","\u016b":"u","\u016d":"u","\u016f":"u","\u0171":"u","\u0173":"u","\u0174":"W","\u0175":"w","\u0176":"Y","\u0177":"y","\u0178":"Y","\u0179":"Z","\u017b":"Z","\u017d":"Z","\u017a":"z","\u017c":"z","\u017e":"z","\u0132":"IJ","\u0133":"ij","\u0152":"Oe","\u0153":"oe","\u0149":"'n","\u017f":"s"}),Qt=Ft({"&":"&","<":"<",">":">",'"':""","'":"'"});function Kt(e){return"\\"+et[e]}function Zt(e){return Ge.test(e)}function Xt(e){var t=-1,n=Array(e.size);return e.forEach((function(e,i){n[++t]=[i,e]})),n}function en(e,t){return function(n){return e(t(n))}}function tn(e,t){for(var n=-1,i=e.length,r=0,s=[];++n",""":'"',"'":"'"}),ln=function e(t){var n,i=(t=null==t?st:ln.defaults(st.Object(),t,ln.pick(st,Qe))).Array,re=t.Date,we=t.Error,Se=t.Function,Me=t.Math,xe=t.Object,ke=t.RegExp,De=t.String,Te=t.TypeError,Ce=i.prototype,Oe=xe.prototype,Le=t["__core-js_shared__"],Re=Se.prototype.toString,Ee=Oe.hasOwnProperty,Ae=0,Ie=(n=/[^.]+$/.exec(Le&&Le.keys&&Le.keys.IE_PROTO||""))?"Symbol(src)_1."+n:"",Pe=Oe.toString,je=Re.call(xe),Ne=st._,Fe=ke("^"+Re.call(Ee).replace(te,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),Ye=ct?t.Buffer:r,ze=t.Symbol,$e=t.Uint8Array,He=Ye?Ye.allocUnsafe:r,We=en(xe.getPrototypeOf,xe),Ue=xe.create,Ge=Oe.propertyIsEnumerable,et=Ce.splice,it=ze?ze.isConcatSpreadable:r,rt=ze?ze.iterator:r,ot=ze?ze.toStringTag:r,at=function(){try{var e=cs(xe,"defineProperty");return e({},"",{}),e}catch(t){}}(),lt=t.clearTimeout!==st.clearTimeout&&t.clearTimeout,ut=re&&re.now!==st.Date.now&&re.now,Lt=t.setTimeout!==st.setTimeout&&t.setTimeout,Ft=Me.ceil,un=Me.floor,dn=xe.getOwnPropertySymbols,hn=Ye?Ye.isBuffer:r,fn=t.isFinite,pn=Ce.join,mn=en(xe.keys,xe),bn=Me.max,gn=Me.min,_n=re.now,yn=t.parseInt,vn=Me.random,wn=Ce.reverse,Sn=cs(t,"DataView"),Mn=cs(t,"Map"),xn=cs(t,"Promise"),kn=cs(t,"Set"),Dn=cs(t,"WeakMap"),Tn=cs(xe,"create"),Cn=Dn&&new Dn,On={},Ln=Ns(Sn),Rn=Ns(Mn),En=Ns(xn),An=Ns(kn),In=Ns(Dn),Pn=ze?ze.prototype:r,jn=Pn?Pn.valueOf:r,Nn=Pn?Pn.toString:r;function Fn(e){if(ta(e)&&!Vo(e)&&!(e instanceof Hn)){if(e instanceof $n)return e;if(Ee.call(e,"__wrapped__"))return Fs(e)}return new $n(e)}var Yn=function(){function e(){}return function(t){if(!ea(t))return{};if(Ue)return Ue(t);e.prototype=t;var n=new e;return e.prototype=r,n}}();function zn(){}function $n(e,t){this.__wrapped__=e,this.__actions__=[],this.__chain__=!!t,this.__index__=0,this.__values__=r}function Hn(e){this.__wrapped__=e,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=f,this.__views__=[]}function Wn(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t=t?e:t)),e}function oi(e,t,n,i,s,o){var a,c=1&t,l=2&t,u=4&t;if(n&&(a=s?n(e,i,s,o):n(e)),a!==r)return a;if(!ea(e))return e;var d=Vo(e);if(d){if(a=function(e){var t=e.length,n=new e.constructor(t);return t&&"string"==typeof e[0]&&Ee.call(e,"index")&&(n.index=e.index,n.input=e.input),n}(e),!c)return Dr(e,a)}else{var h=ds(e),f=h==v||h==w;if(Go(e))return vr(e,c);if(h==x||h==m||f&&!s){if(a=l||f?{}:fs(e),!c)return l?function(e,t){return Tr(e,us(e),t)}(e,function(e,t){return e&&Tr(t,Ea(t),e)}(a,e)):function(e,t){return Tr(e,ls(e),t)}(e,ni(a,e))}else{if(!Xe[h])return s?e:{};a=function(e,t,n){var i=e.constructor;switch(t){case R:return wr(e);case g:case _:return new i(+e);case E:return function(e,t){var n=t?wr(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.byteLength)}(e,n);case A:case I:case P:case j:case N:case F:case Y:case z:case $:return Sr(e,n);case S:return new i;case M:case C:return new i(e);case D:return function(e){var t=new e.constructor(e.source,he.exec(e));return t.lastIndex=e.lastIndex,t}(e);case T:return new i;case O:return jn?xe(jn.call(e)):{}}}(e,h,c)}}o||(o=new qn);var p=o.get(e);if(p)return p;o.set(e,a),oa(e)?e.forEach((function(i){a.add(oi(i,t,n,i,e,o))})):na(e)&&e.forEach((function(i,r){a.set(r,oi(i,t,n,r,e,o))}));var b=d?r:(u?l?ts:es:l?Ea:Ra)(e);return yt(b||e,(function(i,r){b&&(i=e[r=i]),Xn(a,r,oi(i,t,n,r,e,o))})),a}function ai(e,t,n){var i=n.length;if(null==e)return!i;for(e=xe(e);i--;){var s=n[i],o=e[s];if(o===r&&!(s in e)||!(0,t[s])(o))return!1}return!0}function ci(e,t,n){if("function"!=typeof e)throw new Te(s);return Cs((function(){e.apply(r,n)}),t)}function li(e,t,n,i){var r=-1,s=Mt,o=!0,a=e.length,c=[],l=t.length;if(!a)return c;n&&(t=kt(t,Wt(n))),i?(s=xt,o=!1):t.length>=200&&(s=Bt,o=!1,t=new Un(t));e:for(;++r-1},Vn.prototype.set=function(e,t){var n=this.__data__,i=ei(n,e);return i<0?(++this.size,n.push([e,t])):n[i][1]=t,this},Bn.prototype.clear=function(){this.size=0,this.__data__={hash:new Wn,map:new(Mn||Vn),string:new Wn}},Bn.prototype.delete=function(e){var t=os(this,e).delete(e);return this.size-=t?1:0,t},Bn.prototype.get=function(e){return os(this,e).get(e)},Bn.prototype.has=function(e){return os(this,e).has(e)},Bn.prototype.set=function(e,t){var n=os(this,e),i=n.size;return n.set(e,t),this.size+=n.size==i?0:1,this},Un.prototype.add=Un.prototype.push=function(e){return this.__data__.set(e,o),this},Un.prototype.has=function(e){return this.__data__.has(e)},qn.prototype.clear=function(){this.__data__=new Vn,this.size=0},qn.prototype.delete=function(e){var t=this.__data__,n=t.delete(e);return this.size=t.size,n},qn.prototype.get=function(e){return this.__data__.get(e)},qn.prototype.has=function(e){return this.__data__.has(e)},qn.prototype.set=function(e,t){var n=this.__data__;if(n instanceof Vn){var i=n.__data__;if(!Mn||i.length<199)return i.push([e,t]),this.size=++n.size,this;n=this.__data__=new Bn(i)}return n.set(e,t),this.size=n.size,this};var ui=Lr(_i),di=Lr(yi,!0);function hi(e,t){var n=!0;return ui(e,(function(e,i,r){return n=!!t(e,i,r)})),n}function fi(e,t,n){for(var i=-1,s=e.length;++i0&&n(a)?t>1?mi(a,t-1,n,i,r):Dt(r,a):i||(r[r.length]=a)}return r}var bi=Rr(),gi=Rr(!0);function _i(e,t){return e&&bi(e,t,Ra)}function yi(e,t){return e&&gi(e,t,Ra)}function vi(e,t){return St(t,(function(t){return Ko(e[t])}))}function wi(e,t){for(var n=0,i=(t=br(t,e)).length;null!=e&&nt}function ki(e,t){return null!=e&&Ee.call(e,t)}function Di(e,t){return null!=e&&t in xe(e)}function Ti(e,t,n){for(var s=n?xt:Mt,o=e[0].length,a=e.length,c=a,l=i(a),u=1/0,d=[];c--;){var h=e[c];c&&t&&(h=kt(h,Wt(t))),u=gn(h.length,u),l[c]=!n&&(t||o>=120&&h.length>=120)?new Un(c&&h):r}h=e[0];var f=-1,p=l[0];e:for(;++f=a?c:c*("desc"==n[i]?-1:1)}return e.index-t.index}(e,t,n)}));i--;)e[i]=e[i].value;return e}(ji(e,(function(e,n,r){return{criteria:kt(t,(function(t){return t(e)})),index:++i,value:e}})))}function Hi(e,t,n){for(var i=-1,r=t.length,s={};++i-1;)a!==e&&et.call(a,c,1),et.call(e,c,1);return e}function Vi(e,t){for(var n=e?t.length:0,i=n-1;n--;){var r=t[n];if(n==i||r!==s){var s=r;ms(r)?et.call(e,r,1):cr(e,r)}}return e}function Bi(e,t){return e+un(vn()*(t-e+1))}function Ui(e,t){var n="";if(!e||t<1||t>d)return n;do{t%2&&(n+=e),(t=un(t/2))&&(e+=e)}while(t);return n}function qi(e,t){return Os(Ms(e,t,ic),e+"")}function Gi(e){return Jn(za(e))}function Ji(e,t){var n=za(e);return Es(n,si(t,0,n.length))}function Qi(e,t,n,i){if(!ea(e))return e;for(var s=-1,o=(t=br(t,e)).length,a=o-1,c=e;null!=c&&++ss?0:s+t),(n=n>s?s:n)<0&&(n+=s),s=t>n?0:n-t>>>0,t>>>=0;for(var o=i(s);++r>>1,o=e[s];null!==o&&!ca(o)&&(n?o<=t:o=200){var l=t?null:Ur(e);if(l)return nn(l);o=!1,r=Bt,c=new Un}else c=t?[]:a;e:for(;++i=i?e:er(e,t,n)}var yr=lt||function(e){return st.clearTimeout(e)};function vr(e,t){if(t)return e.slice();var n=e.length,i=He?He(n):new e.constructor(n);return e.copy(i),i}function wr(e){var t=new e.constructor(e.byteLength);return new $e(t).set(new $e(e)),t}function Sr(e,t){var n=t?wr(e.buffer):e.buffer;return new e.constructor(n,e.byteOffset,e.length)}function Mr(e,t){if(e!==t){var n=e!==r,i=null===e,s=e==e,o=ca(e),a=t!==r,c=null===t,l=t==t,u=ca(t);if(!c&&!u&&!o&&e>t||o&&a&&l&&!c&&!u||i&&a&&l||!n&&l||!s)return 1;if(!i&&!o&&!u&&e1?n[s-1]:r,a=s>2?n[2]:r;for(o=e.length>3&&"function"==typeof o?(s--,o):r,a&&bs(n[0],n[1],a)&&(o=s<3?r:o,s=1),t=xe(t);++i-1?s[o?t[a]:a]:r}}function jr(e){return Xr((function(t){var n=t.length,i=n,o=$n.prototype.thru;for(e&&t.reverse();i--;){var a=t[i];if("function"!=typeof a)throw new Te(s);if(o&&!c&&"wrapper"==is(a))var c=new $n([],!0)}for(i=c?i:n;++i1&&y.reverse(),f&&dc))return!1;var u=o.get(e),d=o.get(t);if(u&&d)return u==t&&d==e;var h=-1,f=!0,p=2&n?new Un:r;for(o.set(e,t),o.set(t,e);++h-1&&e%1==0&&e1?"& ":"")+t[i],t=t.join(n>2?", ":" "),e.replace(se,"{\n/* [wrapped with "+t+"] */\n")}(i,function(e,t){return yt(p,(function(n){var i="_."+n[0];t&n[1]&&!Mt(e,i)&&e.push(i)})),e.sort()}(function(e){var t=e.match(oe);return t?t[1].split(ae):[]}(i),n)))}function Rs(e){var t=0,n=0;return function(){var i=_n(),s=16-(i-n);if(n=i,s>0){if(++t>=800)return arguments[0]}else t=0;return e.apply(r,arguments)}}function Es(e,t){var n=-1,i=e.length,s=i-1;for(t=t===r?i:t;++n1?e[t-1]:r;return n="function"==typeof n?(e.pop(),n):r,ro(e,n)}));function ho(e){var t=Fn(e);return t.__chain__=!0,t}function fo(e,t){return t(e)}var po=Xr((function(e){var t=e.length,n=t?e[0]:0,i=this.__wrapped__,s=function(t){return ri(t,e)};return!(t>1||this.__actions__.length)&&i instanceof Hn&&ms(n)?((i=i.slice(n,+n+(t?1:0))).__actions__.push({func:fo,args:[s],thisArg:r}),new $n(i,this.__chain__).thru((function(e){return t&&!e.length&&e.push(r),e}))):this.thru(s)})),mo=Cr((function(e,t,n){Ee.call(e,n)?++e[n]:ii(e,n,1)})),bo=Pr(Hs),go=Pr(Ws);function _o(e,t){return(Vo(e)?yt:ui)(e,ss(t,3))}function yo(e,t){return(Vo(e)?vt:di)(e,ss(t,3))}var vo=Cr((function(e,t,n){Ee.call(e,n)?e[n].push(t):ii(e,n,[t])})),wo=qi((function(e,t,n){var r=-1,s="function"==typeof t,o=Uo(e)?i(e.length):[];return ui(e,(function(e){o[++r]=s?gt(t,e,n):Ci(e,t,n)})),o})),So=Cr((function(e,t,n){ii(e,n,t)}));function Mo(e,t){return(Vo(e)?kt:ji)(e,ss(t,3))}var xo=Cr((function(e,t,n){e[n?0:1].push(t)}),(function(){return[[],[]]})),ko=qi((function(e,t){if(null==e)return[];var n=t.length;return n>1&&bs(e,t[0],t[1])?t=[]:n>2&&bs(t[0],t[1],t[2])&&(t=[t[0]]),$i(e,mi(t,1),[])})),Do=ut||function(){return st.Date.now()};function To(e,t,n){return t=n?r:t,Gr(e,l,r,r,r,r,t=e&&null==t?e.length:t)}function Co(e,t){var n;if("function"!=typeof t)throw new Te(s);return e=pa(e),function(){return--e>0&&(n=t.apply(this,arguments)),e<=1&&(t=r),n}}var Oo=qi((function(e,t,n){var i=1;if(n.length){var r=tn(n,rs(Oo));i|=c}return Gr(e,i,t,n,r)})),Lo=qi((function(e,t,n){var i=3;if(n.length){var r=tn(n,rs(Lo));i|=c}return Gr(t,i,e,n,r)}));function Ro(e,t,n){var i,o,a,c,l,u,d=0,h=!1,f=!1,p=!0;if("function"!=typeof e)throw new Te(s);function m(t){var n=i,s=o;return i=o=r,d=t,c=e.apply(s,n)}function b(e){return d=e,l=Cs(_,t),h?m(e):c}function g(e){var n=e-u;return u===r||n>=t||n<0||f&&e-d>=a}function _(){var e=Do();if(g(e))return y(e);l=Cs(_,function(e){var n=t-(e-u);return f?gn(n,a-(e-d)):n}(e))}function y(e){return l=r,p&&i?m(e):(i=o=r,c)}function v(){var e=Do(),n=g(e);if(i=arguments,o=this,u=e,n){if(l===r)return b(u);if(f)return yr(l),l=Cs(_,t),m(u)}return l===r&&(l=Cs(_,t)),c}return t=ba(t)||0,ea(n)&&(h=!!n.leading,a=(f="maxWait"in n)?bn(ba(n.maxWait)||0,t):a,p="trailing"in n?!!n.trailing:p),v.cancel=function(){l!==r&&yr(l),d=0,i=u=o=l=r},v.flush=function(){return l===r?c:y(Do())},v}var Eo=qi((function(e,t){return ci(e,1,t)})),Ao=qi((function(e,t,n){return ci(e,ba(t)||0,n)}));function Io(e,t){if("function"!=typeof e||null!=t&&"function"!=typeof t)throw new Te(s);var n=function(){var i=arguments,r=t?t.apply(this,i):i[0],s=n.cache;if(s.has(r))return s.get(r);var o=e.apply(this,i);return n.cache=s.set(r,o)||s,o};return n.cache=new(Io.Cache||Bn),n}function Po(e){if("function"!=typeof e)throw new Te(s);return function(){var t=arguments;switch(t.length){case 0:return!e.call(this);case 1:return!e.call(this,t[0]);case 2:return!e.call(this,t[0],t[1]);case 3:return!e.call(this,t[0],t[1],t[2])}return!e.apply(this,t)}}Io.Cache=Bn;var jo=gr((function(e,t){var n=(t=1==t.length&&Vo(t[0])?kt(t[0],Wt(ss())):kt(mi(t,1),Wt(ss()))).length;return qi((function(i){for(var r=-1,s=gn(i.length,n);++r=t})),Wo=Oi(function(){return arguments}())?Oi:function(e){return ta(e)&&Ee.call(e,"callee")&&!Ge.call(e,"callee")},Vo=i.isArray,Bo=dt?Wt(dt):function(e){return ta(e)&&Mi(e)==R};function Uo(e){return null!=e&&Xo(e.length)&&!Ko(e)}function qo(e){return ta(e)&&Uo(e)}var Go=hn||bc,Jo=ht?Wt(ht):function(e){return ta(e)&&Mi(e)==_};function Qo(e){if(!ta(e))return!1;var t=Mi(e);return t==y||"[object DOMException]"==t||"string"==typeof e.message&&"string"==typeof e.name&&!ra(e)}function Ko(e){if(!ea(e))return!1;var t=Mi(e);return t==v||t==w||"[object AsyncFunction]"==t||"[object Proxy]"==t}function Zo(e){return"number"==typeof e&&e==pa(e)}function Xo(e){return"number"==typeof e&&e>-1&&e%1==0&&e<=d}function ea(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}function ta(e){return null!=e&&"object"==typeof e}var na=ft?Wt(ft):function(e){return ta(e)&&ds(e)==S};function ia(e){return"number"==typeof e||ta(e)&&Mi(e)==M}function ra(e){if(!ta(e)||Mi(e)!=x)return!1;var t=We(e);if(null===t)return!0;var n=Ee.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&Re.call(n)==je}var sa=pt?Wt(pt):function(e){return ta(e)&&Mi(e)==D},oa=mt?Wt(mt):function(e){return ta(e)&&ds(e)==T};function aa(e){return"string"==typeof e||!Vo(e)&&ta(e)&&Mi(e)==C}function ca(e){return"symbol"==typeof e||ta(e)&&Mi(e)==O}var la=bt?Wt(bt):function(e){return ta(e)&&Xo(e.length)&&!!Ze[Mi(e)]},ua=Wr(Pi),da=Wr((function(e,t){return e<=t}));function ha(e){if(!e)return[];if(Uo(e))return aa(e)?on(e):Dr(e);if(rt&&e[rt])return function(e){for(var t,n=[];!(t=e.next()).done;)n.push(t.value);return n}(e[rt]());var t=ds(e);return(t==S?Xt:t==T?nn:za)(e)}function fa(e){return e?(e=ba(e))===u||e===-1/0?17976931348623157e292*(e<0?-1:1):e==e?e:0:0===e?e:0}function pa(e){var t=fa(e),n=t%1;return t==t?n?t-n:t:0}function ma(e){return e?si(pa(e),0,f):0}function ba(e){if("number"==typeof e)return e;if(ca(e))return h;if(ea(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=ea(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=Ht(e);var n=pe.test(e);return n||be.test(e)?nt(e.slice(2),n?2:8):fe.test(e)?h:+e}function ga(e){return Tr(e,Ea(e))}function _a(e){return null==e?"":or(e)}var ya=Or((function(e,t){if(vs(t)||Uo(t))Tr(t,Ra(t),e);else for(var n in t)Ee.call(t,n)&&Xn(e,n,t[n])})),va=Or((function(e,t){Tr(t,Ea(t),e)})),wa=Or((function(e,t,n,i){Tr(t,Ea(t),e,i)})),Sa=Or((function(e,t,n,i){Tr(t,Ra(t),e,i)})),Ma=Xr(ri),xa=qi((function(e,t){e=xe(e);var n=-1,i=t.length,s=i>2?t[2]:r;for(s&&bs(t[0],t[1],s)&&(i=1);++n1),t})),Tr(e,ts(e),n),i&&(n=oi(n,7,Kr));for(var r=t.length;r--;)cr(n,t[r]);return n})),ja=Xr((function(e,t){return null==e?{}:function(e,t){return Hi(e,t,(function(t,n){return Ta(e,n)}))}(e,t)}));function Na(e,t){if(null==e)return{};var n=kt(ts(e),(function(e){return[e]}));return t=ss(t),Hi(e,n,(function(e,n){return t(e,n[0])}))}var Fa=qr(Ra),Ya=qr(Ea);function za(e){return null==e?[]:Vt(e,Ra(e))}var $a=Ar((function(e,t,n){return t=t.toLowerCase(),e+(n?Ha(t):t)}));function Ha(e){return Qa(_a(e).toLowerCase())}function Wa(e){return(e=_a(e))&&e.replace(_e,Jt).replace(Be,"")}var Va=Ar((function(e,t,n){return e+(n?"-":"")+t.toLowerCase()})),Ba=Ar((function(e,t,n){return e+(n?" ":"")+t.toLowerCase()})),Ua=Er("toLowerCase"),qa=Ar((function(e,t,n){return e+(n?"_":"")+t.toLowerCase()})),Ga=Ar((function(e,t,n){return e+(n?" ":"")+Qa(t)})),Ja=Ar((function(e,t,n){return e+(n?" ":"")+t.toUpperCase()})),Qa=Er("toUpperCase");function Ka(e,t,n){return e=_a(e),(t=n?r:t)===r?function(e){return Je.test(e)}(e)?function(e){return e.match(qe)||[]}(e):function(e){return e.match(ce)||[]}(e):e.match(t)||[]}var Za=qi((function(e,t){try{return gt(e,r,t)}catch(n){return Qo(n)?n:new we(n)}})),Xa=Xr((function(e,t){return yt(t,(function(t){t=js(t),ii(e,t,Oo(e[t],e))})),e}));function ec(e){return function(){return e}}var tc=jr(),nc=jr(!0);function ic(e){return e}function rc(e){return Ai("function"==typeof e?e:oi(e,1))}var sc=qi((function(e,t){return function(n){return Ci(n,e,t)}})),oc=qi((function(e,t){return function(n){return Ci(e,n,t)}}));function ac(e,t,n){var i=Ra(t),r=vi(t,i);null!=n||ea(t)&&(r.length||!i.length)||(n=t,t=e,e=this,r=vi(t,Ra(t)));var s=!(ea(n)&&"chain"in n&&!n.chain),o=Ko(e);return yt(r,(function(n){var i=t[n];e[n]=i,o&&(e.prototype[n]=function(){var t=this.__chain__;if(s||t){var n=e(this.__wrapped__),r=n.__actions__=Dr(this.__actions__);return r.push({func:i,args:arguments,thisArg:e}),n.__chain__=t,n}return i.apply(e,Dt([this.value()],arguments))})})),e}function cc(){}var lc=zr(kt),uc=zr(wt),dc=zr(Ot);function hc(e){return gs(e)?Nt(js(e)):function(e){return function(t){return wi(t,e)}}(e)}var fc=Hr(),pc=Hr(!0);function mc(){return[]}function bc(){return!1}var gc,_c=Yr((function(e,t){return e+t}),0),yc=Br("ceil"),vc=Yr((function(e,t){return e/t}),1),wc=Br("floor"),Sc=Yr((function(e,t){return e*t}),1),Mc=Br("round"),xc=Yr((function(e,t){return e-t}),0);return Fn.after=function(e,t){if("function"!=typeof t)throw new Te(s);return e=pa(e),function(){if(--e<1)return t.apply(this,arguments)}},Fn.ary=To,Fn.assign=ya,Fn.assignIn=va,Fn.assignInWith=wa,Fn.assignWith=Sa,Fn.at=Ma,Fn.before=Co,Fn.bind=Oo,Fn.bindAll=Xa,Fn.bindKey=Lo,Fn.castArray=function(){if(!arguments.length)return[];var e=arguments[0];return Vo(e)?e:[e]},Fn.chain=ho,Fn.chunk=function(e,t,n){t=(n?bs(e,t,n):t===r)?1:bn(pa(t),0);var s=null==e?0:e.length;if(!s||t<1)return[];for(var o=0,a=0,c=i(Ft(s/t));os?0:s+n),(i=i===r||i>s?s:pa(i))<0&&(i+=s),i=n>i?0:ma(i);n>>0)?(e=_a(e))&&("string"==typeof t||null!=t&&!sa(t))&&!(t=or(t))&&Zt(e)?_r(on(e),0,n):e.split(t,n):[]},Fn.spread=function(e,t){if("function"!=typeof e)throw new Te(s);return t=null==t?0:bn(pa(t),0),qi((function(n){var i=n[t],r=_r(n,0,t);return i&&Dt(r,i),gt(e,this,r)}))},Fn.tail=function(e){var t=null==e?0:e.length;return t?er(e,1,t):[]},Fn.take=function(e,t,n){return e&&e.length?er(e,0,(t=n||t===r?1:pa(t))<0?0:t):[]},Fn.takeRight=function(e,t,n){var i=null==e?0:e.length;return i?er(e,(t=i-(t=n||t===r?1:pa(t)))<0?0:t,i):[]},Fn.takeRightWhile=function(e,t){return e&&e.length?ur(e,ss(t,3),!1,!0):[]},Fn.takeWhile=function(e,t){return e&&e.length?ur(e,ss(t,3)):[]},Fn.tap=function(e,t){return t(e),e},Fn.throttle=function(e,t,n){var i=!0,r=!0;if("function"!=typeof e)throw new Te(s);return ea(n)&&(i="leading"in n?!!n.leading:i,r="trailing"in n?!!n.trailing:r),Ro(e,t,{leading:i,maxWait:t,trailing:r})},Fn.thru=fo,Fn.toArray=ha,Fn.toPairs=Fa,Fn.toPairsIn=Ya,Fn.toPath=function(e){return Vo(e)?kt(e,js):ca(e)?[e]:Dr(Ps(_a(e)))},Fn.toPlainObject=ga,Fn.transform=function(e,t,n){var i=Vo(e),r=i||Go(e)||la(e);if(t=ss(t,4),null==n){var s=e&&e.constructor;n=r?i?new s:[]:ea(e)&&Ko(s)?Yn(We(e)):{}}return(r?yt:_i)(e,(function(e,i,r){return t(n,e,i,r)})),n},Fn.unary=function(e){return To(e,1)},Fn.union=eo,Fn.unionBy=to,Fn.unionWith=no,Fn.uniq=function(e){return e&&e.length?ar(e):[]},Fn.uniqBy=function(e,t){return e&&e.length?ar(e,ss(t,2)):[]},Fn.uniqWith=function(e,t){return t="function"==typeof t?t:r,e&&e.length?ar(e,r,t):[]},Fn.unset=function(e,t){return null==e||cr(e,t)},Fn.unzip=io,Fn.unzipWith=ro,Fn.update=function(e,t,n){return null==e?e:lr(e,t,mr(n))},Fn.updateWith=function(e,t,n,i){return i="function"==typeof i?i:r,null==e?e:lr(e,t,mr(n),i)},Fn.values=za,Fn.valuesIn=function(e){return null==e?[]:Vt(e,Ea(e))},Fn.without=so,Fn.words=Ka,Fn.wrap=function(e,t){return No(mr(t),e)},Fn.xor=oo,Fn.xorBy=ao,Fn.xorWith=co,Fn.zip=lo,Fn.zipObject=function(e,t){return fr(e||[],t||[],Xn)},Fn.zipObjectDeep=function(e,t){return fr(e||[],t||[],Qi)},Fn.zipWith=uo,Fn.entries=Fa,Fn.entriesIn=Ya,Fn.extend=va,Fn.extendWith=wa,ac(Fn,Fn),Fn.add=_c,Fn.attempt=Za,Fn.camelCase=$a,Fn.capitalize=Ha,Fn.ceil=yc,Fn.clamp=function(e,t,n){return n===r&&(n=t,t=r),n!==r&&(n=(n=ba(n))==n?n:0),t!==r&&(t=(t=ba(t))==t?t:0),si(ba(e),t,n)},Fn.clone=function(e){return oi(e,4)},Fn.cloneDeep=function(e){return oi(e,5)},Fn.cloneDeepWith=function(e,t){return oi(e,5,t="function"==typeof t?t:r)},Fn.cloneWith=function(e,t){return oi(e,4,t="function"==typeof t?t:r)},Fn.conformsTo=function(e,t){return null==t||ai(e,t,Ra(t))},Fn.deburr=Wa,Fn.defaultTo=function(e,t){return null==e||e!=e?t:e},Fn.divide=vc,Fn.endsWith=function(e,t,n){e=_a(e),t=or(t);var i=e.length,s=n=n===r?i:si(pa(n),0,i);return(n-=t.length)>=0&&e.slice(n,s)==t},Fn.eq=zo,Fn.escape=function(e){return(e=_a(e))&&G.test(e)?e.replace(U,Qt):e},Fn.escapeRegExp=function(e){return(e=_a(e))&&ne.test(e)?e.replace(te,"\\$&"):e},Fn.every=function(e,t,n){var i=Vo(e)?wt:hi;return n&&bs(e,t,n)&&(t=r),i(e,ss(t,3))},Fn.find=bo,Fn.findIndex=Hs,Fn.findKey=function(e,t){return Rt(e,ss(t,3),_i)},Fn.findLast=go,Fn.findLastIndex=Ws,Fn.findLastKey=function(e,t){return Rt(e,ss(t,3),yi)},Fn.floor=wc,Fn.forEach=_o,Fn.forEachRight=yo,Fn.forIn=function(e,t){return null==e?e:bi(e,ss(t,3),Ea)},Fn.forInRight=function(e,t){return null==e?e:gi(e,ss(t,3),Ea)},Fn.forOwn=function(e,t){return e&&_i(e,ss(t,3))},Fn.forOwnRight=function(e,t){return e&&yi(e,ss(t,3))},Fn.get=Da,Fn.gt=$o,Fn.gte=Ho,Fn.has=function(e,t){return null!=e&&hs(e,t,ki)},Fn.hasIn=Ta,Fn.head=Bs,Fn.identity=ic,Fn.includes=function(e,t,n,i){e=Uo(e)?e:za(e),n=n&&!i?pa(n):0;var r=e.length;return n<0&&(n=bn(r+n,0)),aa(e)?n<=r&&e.indexOf(t,n)>-1:!!r&&At(e,t,n)>-1},Fn.indexOf=function(e,t,n){var i=null==e?0:e.length;if(!i)return-1;var r=null==n?0:pa(n);return r<0&&(r=bn(i+r,0)),At(e,t,r)},Fn.inRange=function(e,t,n){return t=fa(t),n===r?(n=t,t=0):n=fa(n),function(e,t,n){return e>=gn(t,n)&&e=-9007199254740991&&e<=d},Fn.isSet=oa,Fn.isString=aa,Fn.isSymbol=ca,Fn.isTypedArray=la,Fn.isUndefined=function(e){return e===r},Fn.isWeakMap=function(e){return ta(e)&&ds(e)==L},Fn.isWeakSet=function(e){return ta(e)&&"[object WeakSet]"==Mi(e)},Fn.join=function(e,t){return null==e?"":pn.call(e,t)},Fn.kebabCase=Va,Fn.last=Js,Fn.lastIndexOf=function(e,t,n){var i=null==e?0:e.length;if(!i)return-1;var s=i;return n!==r&&(s=(s=pa(n))<0?bn(i+s,0):gn(s,i-1)),t==t?function(e,t,n){for(var i=n+1;i--;)if(e[i]===t)return i;return i}(e,t,s):Et(e,Pt,s,!0)},Fn.lowerCase=Ba,Fn.lowerFirst=Ua,Fn.lt=ua,Fn.lte=da,Fn.max=function(e){return e&&e.length?fi(e,ic,xi):r},Fn.maxBy=function(e,t){return e&&e.length?fi(e,ss(t,2),xi):r},Fn.mean=function(e){return jt(e,ic)},Fn.meanBy=function(e,t){return jt(e,ss(t,2))},Fn.min=function(e){return e&&e.length?fi(e,ic,Pi):r},Fn.minBy=function(e,t){return e&&e.length?fi(e,ss(t,2),Pi):r},Fn.stubArray=mc,Fn.stubFalse=bc,Fn.stubObject=function(){return{}},Fn.stubString=function(){return""},Fn.stubTrue=function(){return!0},Fn.multiply=Sc,Fn.nth=function(e,t){return e&&e.length?zi(e,pa(t)):r},Fn.noConflict=function(){return st._===this&&(st._=Ne),this},Fn.noop=cc,Fn.now=Do,Fn.pad=function(e,t,n){e=_a(e);var i=(t=pa(t))?sn(e):0;if(!t||i>=t)return e;var r=(t-i)/2;return $r(un(r),n)+e+$r(Ft(r),n)},Fn.padEnd=function(e,t,n){e=_a(e);var i=(t=pa(t))?sn(e):0;return t&&it){var i=e;e=t,t=i}if(n||e%1||t%1){var s=vn();return gn(e+s*(t-e+tt("1e-"+((s+"").length-1))),t)}return Bi(e,t)},Fn.reduce=function(e,t,n){var i=Vo(e)?Tt:Yt,r=arguments.length<3;return i(e,ss(t,4),n,r,ui)},Fn.reduceRight=function(e,t,n){var i=Vo(e)?Ct:Yt,r=arguments.length<3;return i(e,ss(t,4),n,r,di)},Fn.repeat=function(e,t,n){return t=(n?bs(e,t,n):t===r)?1:pa(t),Ui(_a(e),t)},Fn.replace=function(){var e=arguments,t=_a(e[0]);return e.length<3?t:t.replace(e[1],e[2])},Fn.result=function(e,t,n){var i=-1,s=(t=br(t,e)).length;for(s||(s=1,e=r);++id)return[];var n=f,i=gn(e,f);t=ss(t),e-=f;for(var r=$t(i,t);++n=o)return e;var c=n-sn(i);if(c<1)return i;var l=a?_r(a,0,c).join(""):e.slice(0,c);if(s===r)return l+i;if(a&&(c+=l.length-c),sa(s)){if(e.slice(c).search(s)){var u,d=l;for(s.global||(s=ke(s.source,_a(he.exec(s))+"g")),s.lastIndex=0;u=s.exec(d);)var h=u.index;l=l.slice(0,h===r?c:h)}}else if(e.indexOf(or(s),c)!=c){var f=l.lastIndexOf(s);f>-1&&(l=l.slice(0,f))}return l+i},Fn.unescape=function(e){return(e=_a(e))&&q.test(e)?e.replace(B,cn):e},Fn.uniqueId=function(e){var t=++Ae;return _a(e)+t},Fn.upperCase=Ja,Fn.upperFirst=Qa,Fn.each=_o,Fn.eachRight=yo,Fn.first=Bs,ac(Fn,(gc={},_i(Fn,(function(e,t){Ee.call(Fn.prototype,t)||(gc[t]=e)})),gc),{chain:!1}),Fn.VERSION="4.17.21",yt(["bind","bindKey","curry","curryRight","partial","partialRight"],(function(e){Fn[e].placeholder=Fn})),yt(["drop","take"],(function(e,t){Hn.prototype[e]=function(n){n=n===r?1:bn(pa(n),0);var i=this.__filtered__&&!t?new Hn(this):this.clone();return i.__filtered__?i.__takeCount__=gn(n,i.__takeCount__):i.__views__.push({size:gn(n,f),type:e+(i.__dir__<0?"Right":"")}),i},Hn.prototype[e+"Right"]=function(t){return this.reverse()[e](t).reverse()}})),yt(["filter","map","takeWhile"],(function(e,t){var n=t+1,i=1==n||3==n;Hn.prototype[e]=function(e){var t=this.clone();return t.__iteratees__.push({iteratee:ss(e,3),type:n}),t.__filtered__=t.__filtered__||i,t}})),yt(["head","last"],(function(e,t){var n="take"+(t?"Right":"");Hn.prototype[e]=function(){return this[n](1).value()[0]}})),yt(["initial","tail"],(function(e,t){var n="drop"+(t?"":"Right");Hn.prototype[e]=function(){return this.__filtered__?new Hn(this):this[n](1)}})),Hn.prototype.compact=function(){return this.filter(ic)},Hn.prototype.find=function(e){return this.filter(e).head()},Hn.prototype.findLast=function(e){return this.reverse().find(e)},Hn.prototype.invokeMap=qi((function(e,t){return"function"==typeof e?new Hn(this):this.map((function(n){return Ci(n,e,t)}))})),Hn.prototype.reject=function(e){return this.filter(Po(ss(e)))},Hn.prototype.slice=function(e,t){e=pa(e);var n=this;return n.__filtered__&&(e>0||t<0)?new Hn(n):(e<0?n=n.takeRight(-e):e&&(n=n.drop(e)),t!==r&&(n=(t=pa(t))<0?n.dropRight(-t):n.take(t-e)),n)},Hn.prototype.takeRightWhile=function(e){return this.reverse().takeWhile(e).reverse()},Hn.prototype.toArray=function(){return this.take(f)},_i(Hn.prototype,(function(e,t){var n=/^(?:filter|find|map|reject)|While$/.test(t),i=/^(?:head|last)$/.test(t),s=Fn[i?"take"+("last"==t?"Right":""):t],o=i||/^find/.test(t);s&&(Fn.prototype[t]=function(){var t=this.__wrapped__,a=i?[1]:arguments,c=t instanceof Hn,l=a[0],u=c||Vo(t),d=function(e){var t=s.apply(Fn,Dt([e],a));return i&&h?t[0]:t};u&&n&&"function"==typeof l&&1!=l.length&&(c=u=!1);var h=this.__chain__,f=!!this.__actions__.length,p=o&&!h,m=c&&!f;if(!o&&u){t=m?t:new Hn(this);var b=e.apply(t,a);return b.__actions__.push({func:fo,args:[d],thisArg:r}),new $n(b,h)}return p&&m?e.apply(this,a):(b=this.thru(d),p?i?b.value()[0]:b.value():b)})})),yt(["pop","push","shift","sort","splice","unshift"],(function(e){var t=Ce[e],n=/^(?:push|sort|unshift)$/.test(e)?"tap":"thru",i=/^(?:pop|shift)$/.test(e);Fn.prototype[e]=function(){var e=arguments;if(i&&!this.__chain__){var r=this.value();return t.apply(Vo(r)?r:[],e)}return this[n]((function(n){return t.apply(Vo(n)?n:[],e)}))}})),_i(Hn.prototype,(function(e,t){var n=Fn[t];if(n){var i=n.name+"";Ee.call(On,i)||(On[i]=[]),On[i].push({name:t,func:n})}})),On[Nr(r,2).name]=[{name:"wrapper",func:r}],Hn.prototype.clone=function(){var e=new Hn(this.__wrapped__);return e.__actions__=Dr(this.__actions__),e.__dir__=this.__dir__,e.__filtered__=this.__filtered__,e.__iteratees__=Dr(this.__iteratees__),e.__takeCount__=this.__takeCount__,e.__views__=Dr(this.__views__),e},Hn.prototype.reverse=function(){if(this.__filtered__){var e=new Hn(this);e.__dir__=-1,e.__filtered__=!0}else(e=this.clone()).__dir__*=-1;return e},Hn.prototype.value=function(){var e=this.__wrapped__.value(),t=this.__dir__,n=Vo(e),i=t<0,r=n?e.length:0,s=function(e,t,n){for(var i=-1,r=n.length;++i=this.__values__.length;return{done:e,value:e?r:this.__values__[this.__index__++]}},Fn.prototype.plant=function(e){for(var t,n=this;n instanceof zn;){var i=Fs(n);i.__index__=0,i.__values__=r,t?s.__wrapped__=i:t=i;var s=i;n=n.__wrapped__}return s.__wrapped__=e,t},Fn.prototype.reverse=function(){var e=this.__wrapped__;if(e instanceof Hn){var t=e;return this.__actions__.length&&(t=new Hn(this)),(t=t.reverse()).__actions__.push({func:fo,args:[Xs],thisArg:r}),new $n(t,this.__chain__)}return this.thru(Xs)},Fn.prototype.toJSON=Fn.prototype.valueOf=Fn.prototype.value=function(){return dr(this.__wrapped__,this.__actions__)},Fn.prototype.first=Fn.prototype.head,rt&&(Fn.prototype[rt]=function(){return this}),Fn}();st._=ln,(i=(function(){return ln}).call(t,n,t,e))===r||(e.exports=i)}).call(this)}).call(this,n("YuTi")(e))},MAOJ:function(e,t,n){"use strict";n.d(t,"a",(function(){return u}));var i=n("wd/R"),r=n.n(i),s=n("8Y7J"),o=n("G0yt"),a=n("s7LF"),c=n("SVse");function l(e,t){if(1&e){const e=s.Tb();s.Sb(0,"div",0),s.Sb(1,"ngb-timepicker",4),s.gc("ngModelChange",(function(t){return s.Dc(e),s.ic().time=t}))("ngModelChange",(function(){return s.Dc(e),s.ic().onModelChange()})),s.Rb(),s.Rb()}if(2&e){const e=s.ic();s.yb(1),s.pc("seconds",e.hasSeconds)("ngModel",e.time)}}let u=(()=>{class e{constructor(e){this.calendar=e,this.hasSeconds=!0,this.hasTime=!0}ngOnInit(){var e;this.minDate=this.calendar.getToday(),this.format=this.hasTime?this.hasSeconds?"YYYY-MM-DD HH:mm:ss":"YYYY-MM-DD HH:mm":"YYYY-MM-DD";let t=r()(null===(e=this.control)||void 0===e?void 0:e.value,this.format);t.isValid()&&!t.isBefore(r()())||(t=r()()),this.date={year:t.year(),month:t.month()+1,day:t.date()},this.time={hour:t.hour(),minute:t.minute(),second:t.second()},this.onModelChange()}onModelChange(){if(this.date){const e=Object.assign({},this.date,this.time);e.month--,setTimeout(()=>{this.control.setValue(r()(e).format(this.format))})}else setTimeout(()=>{this.control.setValue("")})}}return e.\u0275fac=function(t){return new(t||e)(s.Mb(o.d))},e.\u0275cmp=s.Gb({type:e,selectors:[["cd-date-time-picker"]],inputs:{control:"control",hasSeconds:"hasSeconds",hasTime:"hasTime"},decls:4,vars:3,consts:[[1,"d-flex","justify-content-center"],[3,"ngModel","minDate","ngModelChange"],["dp",""],["class","d-flex justify-content-center",4,"ngIf"],[3,"seconds","ngModel","ngModelChange"]],template:function(e,t){1&e&&(s.Sb(0,"div",0),s.Sb(1,"ngb-datepicker",1,2),s.gc("ngModelChange",(function(e){return t.date=e}))("ngModelChange",(function(){return t.onModelChange()})),s.Rb(),s.Rb(),s.Mc(3,l,2,2,"div",3)),2&e&&(s.yb(1),s.pc("ngModel",t.date)("minDate",t.minDate),s.yb(2),s.pc("ngIf",t.hasTime))},directives:[o.g,a.q,a.t,c.r,o.B],styles:[""]}),e})()},"MO+k":function(e,t,n){e.exports=function(e){"use strict";e=e&&e.hasOwnProperty("default")?e.default:e;var t={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},n=function(e,n){return function(e){var n={};for(var i in t)t.hasOwnProperty(i)&&(n[t[i]]=i);var r=e.exports={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};for(var s in r)if(r.hasOwnProperty(s)){if(!("channels"in r[s]))throw new Error("missing channels property: "+s);if(!("labels"in r[s]))throw new Error("missing channel labels property: "+s);if(r[s].labels.length!==r[s].channels)throw new Error("channel and label counts mismatch: "+s);var o=r[s].channels,a=r[s].labels;delete r[s].channels,delete r[s].labels,Object.defineProperty(r[s],"channels",{value:o}),Object.defineProperty(r[s],"labels",{value:a})}r.rgb.hsl=function(e){var t,n,i=e[0]/255,r=e[1]/255,s=e[2]/255,o=Math.min(i,r,s),a=Math.max(i,r,s),c=a-o;return a===o?t=0:i===a?t=(r-s)/c:r===a?t=2+(s-i)/c:s===a&&(t=4+(i-r)/c),(t=Math.min(60*t,360))<0&&(t+=360),n=(o+a)/2,[t,100*(a===o?0:n<=.5?c/(a+o):c/(2-a-o)),100*n]},r.rgb.hsv=function(e){var t,n,i,r,s,o=e[0]/255,a=e[1]/255,c=e[2]/255,l=Math.max(o,a,c),u=l-Math.min(o,a,c),d=function(e){return(l-e)/6/u+.5};return 0===u?r=s=0:(s=u/l,t=d(o),n=d(a),i=d(c),o===l?r=i-n:a===l?r=1/3+t-i:c===l&&(r=2/3+n-t),r<0?r+=1:r>1&&(r-=1)),[360*r,100*s,100*l]},r.rgb.hwb=function(e){var t=e[0],n=e[1],i=e[2];return[r.rgb.hsl(e)[0],1/255*Math.min(t,Math.min(n,i))*100,100*(i=1-1/255*Math.max(t,Math.max(n,i)))]},r.rgb.cmyk=function(e){var t,n=e[0]/255,i=e[1]/255,r=e[2]/255;return[100*((1-n-(t=Math.min(1-n,1-i,1-r)))/(1-t)||0),100*((1-i-t)/(1-t)||0),100*((1-r-t)/(1-t)||0),100*t]},r.rgb.keyword=function(e){var i=n[e];if(i)return i;var r,s,o,a=1/0;for(var c in t)if(t.hasOwnProperty(c)){var l=(s=e,o=t[c],Math.pow(s[0]-o[0],2)+Math.pow(s[1]-o[1],2)+Math.pow(s[2]-o[2],2));l.04045?Math.pow((t+.055)/1.055,2.4):t/12.92)+.3576*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)+.1805*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)),100*(.2126*t+.7152*n+.0722*i),100*(.0193*t+.1192*n+.9505*i)]},r.rgb.lab=function(e){var t=r.rgb.xyz(e),n=t[0],i=t[1],s=t[2];return i/=100,s/=108.883,n=(n/=95.047)>.008856?Math.pow(n,1/3):7.787*n+16/116,[116*(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116)-16,500*(n-i),200*(i-(s=s>.008856?Math.pow(s,1/3):7.787*s+16/116))]},r.hsl.rgb=function(e){var t,n,i,r,s,o=e[0]/360,a=e[1]/100,c=e[2]/100;if(0===a)return[s=255*c,s,s];t=2*c-(n=c<.5?c*(1+a):c+a-c*a),r=[0,0,0];for(var l=0;l<3;l++)(i=o+1/3*-(l-1))<0&&i++,i>1&&i--,r[l]=255*(s=6*i<1?t+6*(n-t)*i:2*i<1?n:3*i<2?t+(n-t)*(2/3-i)*6:t);return r},r.hsl.hsv=function(e){var t=e[0],n=e[1]/100,i=e[2]/100,r=n,s=Math.max(i,.01);return n*=(i*=2)<=1?i:2-i,r*=s<=1?s:2-s,[t,100*(0===i?2*r/(s+r):2*n/(i+n)),(i+n)/2*100]},r.hsv.rgb=function(e){var t=e[0]/60,n=e[1]/100,i=e[2]/100,r=Math.floor(t)%6,s=t-Math.floor(t),o=255*i*(1-n),a=255*i*(1-n*s),c=255*i*(1-n*(1-s));switch(i*=255,r){case 0:return[i,c,o];case 1:return[a,i,o];case 2:return[o,i,c];case 3:return[o,a,i];case 4:return[c,o,i];case 5:return[i,o,a]}},r.hsv.hsl=function(e){var t,n,i,r=e[0],s=e[1]/100,o=e[2]/100,a=Math.max(o,.01);return i=(2-s)*o,n=s*a,[r,100*(n=(n/=(t=(2-s)*a)<=1?t:2-t)||0),100*(i/=2)]},r.hwb.rgb=function(e){var t,n,i,r,s,o,a,c=e[0]/360,l=e[1]/100,u=e[2]/100,d=l+u;switch(d>1&&(l/=d,u/=d),i=6*c-(t=Math.floor(6*c)),0!=(1&t)&&(i=1-i),r=l+i*((n=1-u)-l),t){default:case 6:case 0:s=n,o=r,a=l;break;case 1:s=r,o=n,a=l;break;case 2:s=l,o=n,a=r;break;case 3:s=l,o=r,a=n;break;case 4:s=r,o=l,a=n;break;case 5:s=n,o=l,a=r}return[255*s,255*o,255*a]},r.cmyk.rgb=function(e){var t=e[1]/100,n=e[2]/100,i=e[3]/100;return[255*(1-Math.min(1,e[0]/100*(1-i)+i)),255*(1-Math.min(1,t*(1-i)+i)),255*(1-Math.min(1,n*(1-i)+i))]},r.xyz.rgb=function(e){var t,n,i,r=e[0]/100,s=e[1]/100,o=e[2]/100;return n=-.9689*r+1.8758*s+.0415*o,i=.0557*r+-.204*s+1.057*o,t=(t=3.2406*r+-1.5372*s+-.4986*o)>.0031308?1.055*Math.pow(t,1/2.4)-.055:12.92*t,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:12.92*n,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:12.92*i,[255*(t=Math.min(Math.max(0,t),1)),255*(n=Math.min(Math.max(0,n),1)),255*(i=Math.min(Math.max(0,i),1))]},r.xyz.lab=function(e){var t=e[0],n=e[1],i=e[2];return n/=100,i/=108.883,t=(t/=95.047)>.008856?Math.pow(t,1/3):7.787*t+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(t-n),200*(n-(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116))]},r.lab.xyz=function(e){var t,n,i;t=e[1]/500+(n=(e[0]+16)/116),i=n-e[2]/200;var r=Math.pow(n,3),s=Math.pow(t,3),o=Math.pow(i,3);return n=r>.008856?r:(n-16/116)/7.787,t=s>.008856?s:(t-16/116)/7.787,i=o>.008856?o:(i-16/116)/7.787,[t*=95.047,n*=100,i*=108.883]},r.lab.lch=function(e){var t,n=e[0],i=e[1],r=e[2];return(t=360*Math.atan2(r,i)/2/Math.PI)<0&&(t+=360),[n,Math.sqrt(i*i+r*r),t]},r.lch.lab=function(e){var t,n=e[1];return t=e[2]/360*2*Math.PI,[e[0],n*Math.cos(t),n*Math.sin(t)]},r.rgb.ansi16=function(e){var t=e[0],n=e[1],i=e[2],s=1 in arguments?arguments[1]:r.rgb.hsv(e)[2];if(0===(s=Math.round(s/50)))return 30;var o=30+(Math.round(i/255)<<2|Math.round(n/255)<<1|Math.round(t/255));return 2===s&&(o+=60),o},r.hsv.ansi16=function(e){return r.rgb.ansi16(r.hsv.rgb(e),e[2])},r.rgb.ansi256=function(e){var t=e[0],n=e[1],i=e[2];return t===n&&n===i?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(n/255*5)+Math.round(i/255*5)},r.ansi16.rgb=function(e){var t=e%10;if(0===t||7===t)return e>50&&(t+=3.5),[t=t/10.5*255,t,t];var n=.5*(1+~~(e>50));return[(1&t)*n*255,(t>>1&1)*n*255,(t>>2&1)*n*255]},r.ansi256.rgb=function(e){if(e>=232){var t=10*(e-232)+8;return[t,t,t]}var n;return e-=16,[Math.floor(e/36)/5*255,Math.floor((n=e%36)/6)/5*255,n%6/5*255]},r.rgb.hex=function(e){var t=(((255&Math.round(e[0]))<<16)+((255&Math.round(e[1]))<<8)+(255&Math.round(e[2]))).toString(16).toUpperCase();return"000000".substring(t.length)+t},r.hex.rgb=function(e){var t=e.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!t)return[0,0,0];var n=t[0];3===t[0].length&&(n=n.split("").map((function(e){return e+e})).join(""));var i=parseInt(n,16);return[i>>16&255,i>>8&255,255&i]},r.rgb.hcg=function(e){var t,n=e[0]/255,i=e[1]/255,r=e[2]/255,s=Math.max(Math.max(n,i),r),o=Math.min(Math.min(n,i),r),a=s-o;return t=a<=0?0:s===n?(i-r)/a%6:s===i?2+(r-n)/a:4+(n-i)/a+4,t/=6,[360*(t%=1),100*a,100*(a<1?o/(1-a):0)]},r.hsl.hcg=function(e){var t,n=e[1]/100,i=e[2]/100,r=0;return(t=i<.5?2*n*i:2*n*(1-i))<1&&(r=(i-.5*t)/(1-t)),[e[0],100*t,100*r]},r.hsv.hcg=function(e){var t=e[2]/100,n=e[1]/100*t,i=0;return n<1&&(i=(t-n)/(1-n)),[e[0],100*n,100*i]},r.hcg.rgb=function(e){var t=e[1]/100,n=e[2]/100;if(0===t)return[255*n,255*n,255*n];var i,r=[0,0,0],s=e[0]/360%1*6,o=s%1,a=1-o;switch(Math.floor(s)){case 0:r[0]=1,r[1]=o,r[2]=0;break;case 1:r[0]=a,r[1]=1,r[2]=0;break;case 2:r[0]=0,r[1]=1,r[2]=o;break;case 3:r[0]=0,r[1]=a,r[2]=1;break;case 4:r[0]=o,r[1]=0,r[2]=1;break;default:r[0]=1,r[1]=0,r[2]=a}return[255*(t*r[0]+(i=(1-t)*n)),255*(t*r[1]+i),255*(t*r[2]+i)]},r.hcg.hsv=function(e){var t=e[1]/100,n=t+e[2]/100*(1-t),i=0;return n>0&&(i=t/n),[e[0],100*i,100*n]},r.hcg.hsl=function(e){var t=e[1]/100,n=e[2]/100*(1-t)+.5*t,i=0;return n>0&&n<.5?i=t/(2*n):n>=.5&&n<1&&(i=t/(2*(1-n))),[e[0],100*i,100*n]},r.hcg.hwb=function(e){var t=e[1]/100,n=t+e[2]/100*(1-t);return[e[0],100*(n-t),100*(1-n)]},r.hwb.hcg=function(e){var t=1-e[2]/100,n=t-e[1]/100,i=0;return n<1&&(i=(t-n)/(1-n)),[e[0],100*n,100*i]},r.apple.rgb=function(e){return[e[0]/65535*255,e[1]/65535*255,e[2]/65535*255]},r.rgb.apple=function(e){return[e[0]/255*65535,e[1]/255*65535,e[2]/255*65535]},r.gray.rgb=function(e){return[e[0]/100*255,e[0]/100*255,e[0]/100*255]},r.gray.hsl=r.gray.hsv=function(e){return[0,0,e[0]]},r.gray.hwb=function(e){return[0,100,e[0]]},r.gray.cmyk=function(e){return[0,0,0,e[0]]},r.gray.lab=function(e){return[e[0],0,0]},r.gray.hex=function(e){var t=255&Math.round(e[0]/100*255),n=((t<<16)+(t<<8)+t).toString(16).toUpperCase();return"000000".substring(n.length)+n},r.rgb.gray=function(e){return[(e[0]+e[1]+e[2])/3/255*100]}}(n={exports:{}}),n.exports}();function i(e,t){return function(n){return t(e(n))}}function r(e,t){for(var r=[t[e].parent,e],s=n[t[e].parent][e],o=t[e].parent;t[o].parent;)r.unshift(t[o].parent),s=i(n[t[o].parent][o],s),o=t[o].parent;return s.conversion=r,s}var s={};Object.keys(n).forEach((function(e){s[e]={},Object.defineProperty(s[e],"channels",{value:n[e].channels}),Object.defineProperty(s[e],"labels",{value:n[e].labels});var t=function(e){for(var t=function(e){var t=function(){for(var e={},t=Object.keys(n),i=t.length,r=0;r1&&(t=Array.prototype.slice.call(arguments));var n=e(t);if("object"==typeof n)for(var i=n.length,r=0;r1&&(t=Array.prototype.slice.call(arguments)),e(t))};return"conversion"in e&&(t.conversion=e.conversion),t}(i)}))}));var o=s,a={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},c={getRgba:l,getHsla:u,getRgb:function(e){var t=l(e);return t&&t.slice(0,3)},getHsl:function(e){var t=u(e);return t&&t.slice(0,3)},getHwb:d,getAlpha:function(e){var t=l(e);return t||(t=u(e))||(t=d(e))?t[3]:void 0},hexString:function(e,t){return t=void 0!==t&&3===e.length?t:e[3],"#"+b(e[0])+b(e[1])+b(e[2])+(t>=0&&t<1?b(Math.round(255*t)):"")},rgbString:function(e,t){return t<1||e[3]&&e[3]<1?h(e,t):"rgb("+e[0]+", "+e[1]+", "+e[2]+")"},rgbaString:h,percentString:function(e,t){return t<1||e[3]&&e[3]<1?f(e,t):"rgb("+Math.round(e[0]/255*100)+"%, "+Math.round(e[1]/255*100)+"%, "+Math.round(e[2]/255*100)+"%)"},percentaString:f,hslString:function(e,t){return t<1||e[3]&&e[3]<1?p(e,t):"hsl("+e[0]+", "+e[1]+"%, "+e[2]+"%)"},hslaString:p,hwbString:function(e,t){return void 0===t&&(t=void 0!==e[3]?e[3]:1),"hwb("+e[0]+", "+e[1]+"%, "+e[2]+"%"+(void 0!==t&&1!==t?", "+t:"")+")"},keyword:function(e){return g[e.slice(0,3)]}};function l(e){if(e){var t=[0,0,0],n=1,i=e.match(/^#([a-fA-F0-9]{3,4})$/i),r="";if(i){r=(i=i[1])[3];for(var s=0;sn?(t+.05)/(n+.05):(n+.05)/(t+.05)},level:function(e){var t=this.contrast(e);return t>=7.1?"AAA":t>=4.5?"AA":""},dark:function(){var e=this.values.rgb;return(299*e[0]+587*e[1]+114*e[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var e=[],t=0;t<3;t++)e[t]=255-this.values.rgb[t];return this.setValues("rgb",e),this},lighten:function(e){var t=this.values.hsl;return t[2]+=t[2]*e,this.setValues("hsl",t),this},darken:function(e){var t=this.values.hsl;return t[2]-=t[2]*e,this.setValues("hsl",t),this},saturate:function(e){var t=this.values.hsl;return t[1]+=t[1]*e,this.setValues("hsl",t),this},desaturate:function(e){var t=this.values.hsl;return t[1]-=t[1]*e,this.setValues("hsl",t),this},whiten:function(e){var t=this.values.hwb;return t[1]+=t[1]*e,this.setValues("hwb",t),this},blacken:function(e){var t=this.values.hwb;return t[2]+=t[2]*e,this.setValues("hwb",t),this},greyscale:function(){var e=this.values.rgb,t=.3*e[0]+.59*e[1]+.11*e[2];return this.setValues("rgb",[t,t,t]),this},clearer:function(e){var t=this.values.alpha;return this.setValues("alpha",t-t*e),this},opaquer:function(e){var t=this.values.alpha;return this.setValues("alpha",t+t*e),this},rotate:function(e){var t=this.values.hsl,n=(t[0]+e)%360;return t[0]=n<0?360+n:n,this.setValues("hsl",t),this},mix:function(e,t){var n=this,i=e,r=void 0===t?.5:t,s=2*r-1,o=n.alpha()-i.alpha(),a=((s*o==-1?s:(s+o)/(1+s*o))+1)/2,c=1-a;return this.rgb(a*n.red()+c*i.red(),a*n.green()+c*i.green(),a*n.blue()+c*i.blue()).alpha(n.alpha()*r+i.alpha()*(1-r))},toJSON:function(){return this.rgb()},clone:function(){var e,t,n=new y,i=this.values,r=n.values;for(var s in i)i.hasOwnProperty(s)&&("[object Array]"===(t={}.toString.call(e=i[s]))?r[s]=e.slice(0):"[object Number]"===t?r[s]=e:console.error("unexpected color value:",e));return n}},y.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},y.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},y.prototype.getValues=function(e){for(var t=this.values,n={},i=0;i=0;r--)t.call(n,e[r],r);else for(r=0;r=1?e:-(Math.sqrt(1-e*e)-1)},easeOutCirc:function(e){return Math.sqrt(1-(e-=1)*e)},easeInOutCirc:function(e){return(e/=.5)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1)},easeInElastic:function(e){var t=1.70158,n=0,i=1;return 0===e?0:1===e?1:(n||(n=.3),i<1?(i=1,t=n/4):t=n/(2*Math.PI)*Math.asin(1/i),-i*Math.pow(2,10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/n))},easeOutElastic:function(e){var t=1.70158,n=0,i=1;return 0===e?0:1===e?1:(n||(n=.3),i<1?(i=1,t=n/4):t=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*e)*Math.sin((e-t)*(2*Math.PI)/n)+1)},easeInOutElastic:function(e){var t=1.70158,n=0,i=1;return 0===e?0:2==(e/=.5)?1:(n||(n=.45),i<1?(i=1,t=n/4):t=n/(2*Math.PI)*Math.asin(1/i),e<1?i*Math.pow(2,10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/n)*-.5:i*Math.pow(2,-10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/n)*.5+1)},easeInBack:function(e){var t=1.70158;return e*e*((t+1)*e-t)},easeOutBack:function(e){var t=1.70158;return(e-=1)*e*((t+1)*e+t)+1},easeInOutBack:function(e){var t=1.70158;return(e/=.5)<1?e*e*((1+(t*=1.525))*e-t)*.5:.5*((e-=2)*e*((1+(t*=1.525))*e+t)+2)},easeInBounce:function(e){return 1-k.easeOutBounce(1-e)},easeOutBounce:function(e){return e<1/2.75?7.5625*e*e:e<2/2.75?7.5625*(e-=1.5/2.75)*e+.75:e<2.5/2.75?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},easeInOutBounce:function(e){return e<.5?.5*k.easeInBounce(2*e):.5*k.easeOutBounce(2*e-1)+.5}},D={effects:k};x.easingEffects=k;var T=Math.PI,C=T/180,O=2*T,L=T/2,R=T/4,E=2*T/3,A={clear:function(e){e.ctx.clearRect(0,0,e.width,e.height)},roundedRect:function(e,t,n,i,r,s){if(s){var o=Math.min(s,r/2,i/2),a=t+o,c=n+o,l=t+i-o,u=n+r-o;e.moveTo(t,c),at.left-n&&e.xt.top-n&&e.y0&&e.requestAnimationFrame()},advance:function(){for(var e,t,n,i,r=this.animations,s=0;s=n?($.callback(e.onAnimationComplete,[e],t),t.animating=!1,r.splice(s,1)):++s}},Q=$.options.resolve,K=["push","pop","shift","splice","unshift"];function Z(e,t){var n=e._chartjs;if(n){var i=n.listeners,r=i.indexOf(t);-1!==r&&i.splice(r,1),i.length>0||(K.forEach((function(t){delete e[t]})),delete e._chartjs)}}var X=function(e,t){this.initialize(e,t)};$.extend(X.prototype,{datasetElementType:null,dataElementType:null,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth"],_dataElementOptions:["backgroundColor","borderColor","borderWidth","pointStyle"],initialize:function(e,t){var n=this;n.chart=e,n.index=t,n.linkScales(),n.addElements(),n._type=n.getMeta().type},updateIndex:function(e){this.index=e},linkScales:function(){var e=this,t=e.getMeta(),n=e.chart,i=n.scales,r=e.getDataset(),s=n.options.scales;null!==t.xAxisID&&t.xAxisID in i&&!r.xAxisID||(t.xAxisID=r.xAxisID||s.xAxes[0].id),null!==t.yAxisID&&t.yAxisID in i&&!r.yAxisID||(t.yAxisID=r.yAxisID||s.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(e){return this.chart.scales[e]},_getValueScaleId:function(){return this.getMeta().yAxisID},_getIndexScaleId:function(){return this.getMeta().xAxisID},_getValueScale:function(){return this.getScaleForId(this._getValueScaleId())},_getIndexScale:function(){return this.getScaleForId(this._getIndexScaleId())},reset:function(){this._update(!0)},destroy:function(){this._data&&Z(this._data,this)},createMetaDataset:function(){var e=this,t=e.datasetElementType;return t&&new t({_chart:e.chart,_datasetIndex:e.index})},createMetaData:function(e){var t=this,n=t.dataElementType;return n&&new n({_chart:t.chart,_datasetIndex:t.index,_index:e})},addElements:function(){var e,t,n=this,i=n.getMeta(),r=n.getDataset().data||[],s=i.data;for(e=0,t=r.length;ei&&e.insertElements(i,r-i)},insertElements:function(e,t){for(var n=0;nr?e.arc(o,a,t.innerRadius-r,i+(s=r/t.innerRadius),n-s,!0):e.arc(o,a,r,i+Math.PI/2,n-Math.PI/2),e.closePath(),e.clip()}j._set("global",{elements:{arc:{backgroundColor:j.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var ie=U.extend({_type:"arc",inLabelRange:function(e){var t=this._view;return!!t&&Math.pow(e-t.x,2)a;)r-=te;for(;r=o&&r<=a&&s>=n.innerRadius&&s<=n.outerRadius}return!1},getCenterPoint:function(){var e=this._view,t=(e.startAngle+e.endAngle)/2,n=(e.innerRadius+e.outerRadius)/2;return{x:e.x+Math.cos(t)*n,y:e.y+Math.sin(t)*n}},getArea:function(){var e=this._view;return Math.PI*((e.endAngle-e.startAngle)/(2*Math.PI))*(Math.pow(e.outerRadius,2)-Math.pow(e.innerRadius,2))},tooltipPosition:function(){var e=this._view,t=e.startAngle+(e.endAngle-e.startAngle)/2,n=(e.outerRadius-e.innerRadius)/2+e.innerRadius;return{x:e.x+Math.cos(t)*n,y:e.y+Math.sin(t)*n}},draw:function(){var e,t=this._chart.ctx,n=this._view,i="inner"===n.borderAlign?.33:0,r={x:n.x,y:n.y,innerRadius:n.innerRadius,outerRadius:Math.max(n.outerRadius-i,0),pixelMargin:i,startAngle:n.startAngle,endAngle:n.endAngle,fullCircles:Math.floor(n.circumference/te)};if(t.save(),t.fillStyle=n.backgroundColor,t.strokeStyle=n.borderColor,r.fullCircles){for(r.endAngle=r.startAngle+te,t.beginPath(),t.arc(r.x,r.y,r.outerRadius,r.startAngle,r.endAngle),t.arc(r.x,r.y,r.innerRadius,r.endAngle,r.startAngle,!0),t.closePath(),e=0;e=s.left&&t<=s.right)&&(r||n>=s.top&&n<=s.bottom)}j._set("global",{elements:{rectangle:{backgroundColor:de,borderColor:de,borderSkipped:"bottom",borderWidth:0}}});var be=U.extend({_type:"rectangle",draw:function(){var e=this._chart.ctx,t=this._view,n=function(e){var t=fe(e),n=t.right-t.left,i=t.bottom-t.top,r=function(e,t,n){var i,r,s,o,a=e.borderWidth,c=function(e){var t=e.borderSkipped,n={};return t?(e.horizontal?e.base>e.x&&(t=pe(t,"left","right")):e.basen?n:i,r:c.right||r<0?0:r>t?t:r,b:c.bottom||s<0?0:s>n?n:s,l:c.left||o<0?0:o>t?t:o}}(e,n/2,i/2);return{outer:{x:t.left,y:t.top,w:n,h:i},inner:{x:t.left+r.l,y:t.top+r.t,w:n-r.l-r.r,h:i-r.t-r.b}}}(t),i=n.outer,r=n.inner;e.fillStyle=t.backgroundColor,e.fillRect(i.x,i.y,i.w,i.h),i.w===r.w&&i.h===r.h||(e.save(),e.beginPath(),e.rect(i.x,i.y,i.w,i.h),e.clip(),e.fillStyle=t.borderColor,e.rect(r.x,r.y,r.w,r.h),e.fill("evenodd"),e.restore())},height:function(){var e=this._view;return e.base-e.y},inRange:function(e,t){return me(this._view,e,t)},inLabelRange:function(e,t){var n=this._view;return he(n)?me(n,e,null):me(n,null,t)},inXRange:function(e){return me(this._view,e,null)},inYRange:function(e){return me(this._view,null,e)},getCenterPoint:function(){var e,t,n=this._view;return he(n)?(e=n.x,t=(n.y+n.base)/2):(e=(n.x+n.base)/2,t=n.y),{x:e,y:t}},getArea:function(){var e=this._view;return he(e)?e.width*Math.abs(e.y-e.base):e.height*Math.abs(e.x-e.base)},tooltipPosition:function(){var e=this._view;return{x:e.x,y:e.y}}}),ge={},_e=oe,ye=ue,ve=be;ge.Arc=ie,ge.Line=_e,ge.Point=ye,ge.Rectangle=ve;var we=$._deprecated,Se=$.valueOrDefault;j._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}}),j._set("global",{datasets:{bar:{categoryPercentage:.8,barPercentage:.9}}});var Me=ee.extend({dataElementType:ge.Rectangle,_dataElementOptions:["backgroundColor","borderColor","borderSkipped","borderWidth","barPercentage","barThickness","categoryPercentage","maxBarThickness","minBarLength"],initialize:function(){var e,t,n=this;ee.prototype.initialize.apply(n,arguments),(e=n.getMeta()).stack=n.getDataset().stack,e.bar=!0,t=n._getIndexScale().options,we("bar chart",t.barPercentage,"scales.[x/y]Axes.barPercentage","dataset.barPercentage"),we("bar chart",t.barThickness,"scales.[x/y]Axes.barThickness","dataset.barThickness"),we("bar chart",t.categoryPercentage,"scales.[x/y]Axes.categoryPercentage","dataset.categoryPercentage"),we("bar chart",n._getValueScale().options.minBarLength,"scales.[x/y]Axes.minBarLength","dataset.minBarLength"),we("bar chart",t.maxBarThickness,"scales.[x/y]Axes.maxBarThickness","dataset.maxBarThickness")},update:function(e){var t,n,i=this,r=i.getMeta().data;for(i._ruler=i.getRuler(),t=0,n=r.length;t=0&&b.min>=0?b.min:b.max,w=void 0===b.start?b.end:b.max>=0&&b.min>=0?b.max-b.min:b.min-b.max,S=m.length;if(_||void 0===_&&void 0!==y)for(i=0;i=0&&l.max>=0?l.max:l.min,(b.min<0&&s<0||b.max>=0&&s>0)&&(v+=s));return o=h.getPixelForValue(v),c=(a=h.getPixelForValue(v+w))-o,void 0!==g&&Math.abs(c)=0&&!f||w<0&&f?o-g:o+g),{size:c,base:o,head:a,center:a+c/2}},calculateBarIndexPixels:function(e,t,n,i){var r="flex"===i.barThickness?function(e,t,n){var i,r=t.pixels,s=r[e],o=e>0?r[e-1]:null,a=e0?Math.min(o,Math.abs(i-n)):o,n=i;return o}(t.scale,t.pixels):-1;return $.isNullOrUndef(s)?(i=c*n.categoryPercentage,r=n.barPercentage):(i=s*o,r=1),{chunk:i/o,ratio:r,start:a-i/2}}(t,n,i),s=this.getStackIndex(e,this.getMeta().stack),o=r.start+r.chunk*s+r.chunk/2,a=Math.min(Se(i.maxBarThickness,1/0),r.chunk*r.ratio);return{base:o-a/2,head:o+a/2,center:o,size:a}},draw:function(){var e=this,t=e.chart,n=e._getValueScale(),i=e.getMeta().data,r=e.getDataset(),s=i.length,o=0;for($.canvas.clipArea(t.ctx,t.chartArea);o=Ce?-Oe:b<-Ce?Oe:0)+p,_=Math.cos(b),y=Math.sin(b),v=Math.cos(g),w=Math.sin(g),S=b<=0&&g>=0||g>=Oe,M=b<=Le&&g>=Le||g>=Oe+Le,x=b<=-Le&&g>=-Le||g>=Ce+Le,k=b===-Ce||g>=Ce?-1:Math.min(_,_*f,v,v*f),D=x?-1:Math.min(y,y*f,w,w*f),T=S?1:Math.max(_,_*f,v,v*f),C=M?1:Math.max(y,y*f,w,w*f);a=(T-k)/2,c=(C-D)/2,l=-(T+k)/2,u=-(C+D)/2}for(t=0,n=h.length;t0&&!isNaN(e)?Oe*(Math.abs(e)/t):0},getMaxBorderWidth:function(e){var t,n,i,r,s,o,a,c,l=0,u=this.chart;if(!e)for(t=0,n=u.data.datasets.length;t(l=(a=o.borderWidth)>l?a:l)?c:l);return l},setHoverStyle:function(e){var t=e._model,n=e._options,i=$.getHoverColor;e.$previousStyle={backgroundColor:t.backgroundColor,borderColor:t.borderColor,borderWidth:t.borderWidth},t.backgroundColor=Te(n.hoverBackgroundColor,i(n.backgroundColor)),t.borderColor=Te(n.hoverBorderColor,i(n.borderColor)),t.borderWidth=Te(n.hoverBorderWidth,n.borderWidth)},_getRingWeightOffset:function(e){for(var t=0,n=0;n0&&Pe(c[e-1]._model,a)&&(n.controlPointPreviousX=l(n.controlPointPreviousX,a.left,a.right),n.controlPointPreviousY=l(n.controlPointPreviousY,a.top,a.bottom)),e0&&(s=e.getDatasetMeta(s[0]._datasetIndex).data),s},"x-axis":function(e,t){return Ke(e,t,{intersect:!1})},point:function(e,t){return Ge(e,Ue(t,e))},nearest:function(e,t,n){var i=Ue(t,e);n.axis=n.axis||"xy";var r=Qe(n.axis);return Je(e,i,n.intersect,r)},x:function(e,t,n){var i=Ue(t,e),r=[],s=!1;return qe(e,(function(e){e.inXRange(i.x)&&r.push(e),e.inRange(i.x,i.y)&&(s=!0)})),n.intersect&&!s&&(r=[]),r},y:function(e,t,n){var i=Ue(t,e),r=[],s=!1;return qe(e,(function(e){e.inYRange(i.y)&&r.push(e),e.inRange(i.x,i.y)&&(s=!0)})),n.intersect&&!s&&(r=[]),r}}},Xe=$.extend;function et(e,t){return $.where(e,(function(e){return e.pos===t}))}function tt(e,t){return e.sort((function(e,n){var i=t?n:e,r=t?e:n;return i.weight===r.weight?i.index-r.index:i.weight-r.weight}))}function nt(e,t,n,i){return Math.max(e[n],t[n])+Math.max(e[i],t[i])}function it(e,t,n){var i,r,s=n.box,o=e.maxPadding;if(n.size&&(e[n.pos]-=n.size),n.size=n.horizontal?s.height:s.width,e[n.pos]+=n.size,s.getPadding){var a=s.getPadding();o.top=Math.max(o.top,a.top),o.left=Math.max(o.left,a.left),o.bottom=Math.max(o.bottom,a.bottom),o.right=Math.max(o.right,a.right)}if(i=t.outerWidth-nt(o,e,"left","right"),r=t.outerHeight-nt(o,e,"top","bottom"),i!==e.w||r!==e.h){e.w=i,e.h=r;var c=n.horizontal?[i,e.w]:[r,e.h];return!(c[0]===c[1]||isNaN(c[0])&&isNaN(c[1]))}}function rt(e,t){var n,i=t.maxPadding;return n={left:0,top:0,right:0,bottom:0},(e?["left","right"]:["top","bottom"]).forEach((function(e){n[e]=Math.max(t[e],i[e])})),n}function st(e,t,n){var i,r,s,o,a,c,l=[];for(i=0,r=e.length;i div {\r\n\tposition: absolute;\r\n\twidth: 1000000px;\r\n\theight: 1000000px;\r\n\tleft: 0;\r\n\ttop: 0;\r\n}\r\n\r\n.chartjs-size-monitor-shrink > div {\r\n\tposition: absolute;\r\n\twidth: 200%;\r\n\theight: 200%;\r\n\tleft: 0;\r\n\ttop: 0;\r\n}\r\n"}))&&at.default||at,ut="chartjs-size-monitor",dt="chartjs-render-monitor",ht=["animationstart","webkitAnimationStart"],ft={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function pt(e,t){var n=$.getStyle(e,t),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}var mt=!!function(){var e=!1;try{var t=Object.defineProperty({},"passive",{get:function(){e=!0}});window.addEventListener("e",null,t)}catch(n){}return e}()&&{passive:!0};function bt(e,t,n){e.addEventListener(t,n,mt)}function gt(e,t,n){e.removeEventListener(t,n,mt)}function _t(e,t,n,i,r){return{type:e,chart:t,native:r||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function yt(e){var t=document.createElement("div");return t.className=e||"",t}var vt={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(e){if(!this.disableCSSInjection){var t=e.getRootNode?e.getRootNode():document;!function(e,t){var n=e.$chartjs||(e.$chartjs={});if(!n.containsStyles){n.containsStyles=!0,t="/* Chart.js */\n"+t;var i=document.createElement("style");i.setAttribute("type","text/css"),i.appendChild(document.createTextNode(t)),e.appendChild(i)}}(t.host?t:document.head,lt)}},acquireContext:function(e,t){"string"==typeof e?e=document.getElementById(e):e.length&&(e=e[0]),e&&e.canvas&&(e=e.canvas);var n=e&&e.getContext&&e.getContext("2d");return n&&n.canvas===e?(this._ensureLoaded(e),function(e,t){var n=e.style,i=e.getAttribute("height"),r=e.getAttribute("width");if(e.$chartjs={initial:{height:i,width:r,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||"block",null===r||""===r){var s=pt(e,"width");void 0!==s&&(e.width=s)}if(null===i||""===i)if(""===e.style.height)e.height=e.width/(t.options.aspectRatio||2);else{var o=pt(e,"height");void 0!==s&&(e.height=o)}}(e,t),n):null},releaseContext:function(e){var t=e.canvas;if(t.$chartjs){var n=t.$chartjs.initial;["height","width"].forEach((function(e){var i=n[e];$.isNullOrUndef(i)?t.removeAttribute(e):t.setAttribute(e,i)})),$.each(n.style||{},(function(e,n){t.style[n]=e})),t.width=t.width,delete t.$chartjs}},addEventListener:function(e,t,n){var i=e.canvas;if("resize"!==t){var r=n.$chartjs||(n.$chartjs={});bt(i,t,(r.proxies||(r.proxies={}))[e.id+"_"+t]=function(t){n(function(e,t){var n=ft[e.type]||e.type,i=$.getRelativePosition(e,t);return _t(n,t,i.x,i.y,e)}(t,e))})}else!function(e,t,n){var i,r,s,o,a=e.$chartjs||(e.$chartjs={}),c=a.resizer=function(e){var t=1e6,n=yt(ut),i=yt(ut+"-expand"),r=yt(ut+"-shrink");i.appendChild(yt()),r.appendChild(yt()),n.appendChild(i),n.appendChild(r),n._reset=function(){i.scrollLeft=t,i.scrollTop=t,r.scrollLeft=t,r.scrollTop=t};var s=function(){n._reset(),e()};return bt(i,"scroll",s.bind(i,"expand")),bt(r,"scroll",s.bind(r,"shrink")),n}((i=function(){if(a.resizer){var i=n.options.maintainAspectRatio&&e.parentNode,r=i?i.clientWidth:0;t(_t("resize",n)),i&&i.clientWidth0){var s=e[0];s.label?n=s.label:s.xLabel?n=s.xLabel:r>0&&s.index-1?e.split("\n"):e}function Ot(e){var t=j.global;return{xPadding:e.xPadding,yPadding:e.yPadding,xAlign:e.xAlign,yAlign:e.yAlign,rtl:e.rtl,textDirection:e.textDirection,bodyFontColor:e.bodyFontColor,_bodyFontFamily:xt(e.bodyFontFamily,t.defaultFontFamily),_bodyFontStyle:xt(e.bodyFontStyle,t.defaultFontStyle),_bodyAlign:e.bodyAlign,bodyFontSize:xt(e.bodyFontSize,t.defaultFontSize),bodySpacing:e.bodySpacing,titleFontColor:e.titleFontColor,_titleFontFamily:xt(e.titleFontFamily,t.defaultFontFamily),_titleFontStyle:xt(e.titleFontStyle,t.defaultFontStyle),titleFontSize:xt(e.titleFontSize,t.defaultFontSize),_titleAlign:e.titleAlign,titleSpacing:e.titleSpacing,titleMarginBottom:e.titleMarginBottom,footerFontColor:e.footerFontColor,_footerFontFamily:xt(e.footerFontFamily,t.defaultFontFamily),_footerFontStyle:xt(e.footerFontStyle,t.defaultFontStyle),footerFontSize:xt(e.footerFontSize,t.defaultFontSize),_footerAlign:e.footerAlign,footerSpacing:e.footerSpacing,footerMarginTop:e.footerMarginTop,caretSize:e.caretSize,cornerRadius:e.cornerRadius,backgroundColor:e.backgroundColor,opacity:0,legendColorBackground:e.multiKeyBackground,displayColors:e.displayColors,borderColor:e.borderColor,borderWidth:e.borderWidth}}function Lt(e,t){return"center"===t?e.x+e.width/2:"right"===t?e.x+e.width-e.xPadding:e.x+e.xPadding}function Rt(e){return Tt([],Ct(e))}var Et=U.extend({initialize:function(){this._model=Ot(this._options),this._lastActive=[]},getTitle:function(){var e=this,t=e._options.callbacks,n=t.beforeTitle.apply(e,arguments),i=t.title.apply(e,arguments),r=t.afterTitle.apply(e,arguments),s=[];return s=Tt(s,Ct(n)),s=Tt(s,Ct(i)),Tt(s,Ct(r))},getBeforeBody:function(){return Rt(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(e,t){var n=this,i=n._options.callbacks,r=[];return $.each(e,(function(e){var s={before:[],lines:[],after:[]};Tt(s.before,Ct(i.beforeLabel.call(n,e,t))),Tt(s.lines,i.label.call(n,e,t)),Tt(s.after,Ct(i.afterLabel.call(n,e,t))),r.push(s)})),r},getAfterBody:function(){return Rt(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var e=this,t=e._options.callbacks,n=t.beforeFooter.apply(e,arguments),i=t.footer.apply(e,arguments),r=t.afterFooter.apply(e,arguments),s=[];return s=Tt(s,Ct(n)),s=Tt(s,Ct(i)),Tt(s,Ct(r))},update:function(e){var t,n,i,r,s,o,a,c,l,u,d=this,h=d._options,f=d._model,p=d._model=Ot(h),m=d._active,b=d._data,g={xAlign:f.xAlign,yAlign:f.yAlign},_={x:f.x,y:f.y},y={width:f.width,height:f.height},v={x:f.caretX,y:f.caretY};if(m.length){p.opacity=1;var w=[],S=[];v=Dt[h.position].call(d,m,d._eventPosition);var M=[];for(t=0,n=m.length;ti.width&&(r=i.width-t.width),r<0&&(r=0)),"top"===c?s+=l:s-="bottom"===c?t.height+l:t.height/2,"center"===c?"left"===a?r+=l:"right"===a&&(r-=l):"left"===a?r-=u:"right"===a&&(r+=u),{x:r,y:s}}(p,y=function(e,t){var n=e._chart.ctx,i=2*t.yPadding,r=0,s=t.body,o=s.reduce((function(e,t){return e+t.before.length+t.lines.length+t.after.length}),0),a=t.title.length,c=t.footer.length,l=t.titleFontSize,u=t.bodyFontSize,d=t.footerFontSize;i+=a*l,i+=a?(a-1)*t.titleSpacing:0,i+=a?t.titleMarginBottom:0,i+=(o+=t.beforeBody.length+t.afterBody.length)*u,i+=o?(o-1)*t.bodySpacing:0,i+=c?t.footerMarginTop:0,i+=c*d,i+=c?(c-1)*t.footerSpacing:0;var h=0,f=function(e){r=Math.max(r,n.measureText(e).width+h)};return n.font=$.fontString(l,t._titleFontStyle,t._titleFontFamily),$.each(t.title,f),n.font=$.fontString(u,t._bodyFontStyle,t._bodyFontFamily),$.each(t.beforeBody.concat(t.afterBody),f),h=t.displayColors?u+2:0,$.each(s,(function(e){$.each(e.before,f),$.each(e.lines,f),$.each(e.after,f)})),h=0,n.font=$.fontString(d,t._footerFontStyle,t._footerFontFamily),$.each(t.footer,f),{width:r+=2*t.xPadding,height:i}}(this,p),g=function(e,t){var n,i,r,s,o,a=e._model,c=e._chart,l=e._chart.chartArea,u="center",d="center";a.yc.height-t.height&&(d="bottom");var h=(l.left+l.right)/2,f=(l.top+l.bottom)/2;"center"===d?(n=function(e){return e<=h},i=function(e){return e>h}):(n=function(e){return e<=t.width/2},i=function(e){return e>=c.width-t.width/2}),r=function(e){return e+t.width+a.caretSize+a.caretPadding>c.width},s=function(e){return e-t.width-a.caretSize-a.caretPadding<0},o=function(e){return e<=f?"top":"bottom"},n(a.x)?(u="left",r(a.x)&&(u="center",d=o(a.y))):i(a.x)&&(u="right",s(a.x)&&(u="center",d=o(a.y)));var p=e._options;return{xAlign:p.xAlign?p.xAlign:u,yAlign:p.yAlign?p.yAlign:d}}(this,y),d._chart)}else p.opacity=0;return p.xAlign=g.xAlign,p.yAlign=g.yAlign,p.x=_.x,p.y=_.y,p.width=y.width,p.height=y.height,p.caretX=v.x,p.caretY=v.y,d._model=p,e&&h.custom&&h.custom.call(d,p),d},drawCaret:function(e,t){var n=this._chart.ctx,i=this.getCaretPosition(e,t,this._view);n.lineTo(i.x1,i.y1),n.lineTo(i.x2,i.y2),n.lineTo(i.x3,i.y3)},getCaretPosition:function(e,t,n){var i,r,s,o,a,c,l=n.caretSize,u=n.cornerRadius,d=n.xAlign,h=n.yAlign,f=e.x,p=e.y,m=t.width,b=t.height;if("center"===h)a=p+b/2,"left"===d?(r=(i=f)-l,s=i,o=a+l,c=a-l):(r=(i=f+m)+l,s=i,o=a-l,c=a+l);else if("left"===d?(i=(r=f+u+l)-l,s=r+l):"right"===d?(i=(r=f+m-u-l)-l,s=r+l):(i=(r=n.caretX)-l,s=r+l),"top"===h)a=(o=p)-l,c=o;else{a=(o=p+b)+l,c=o;var g=s;s=i,i=g}return{x1:i,x2:r,x3:s,y1:o,y2:a,y3:c}},drawTitle:function(e,t,n){var i,r,s,o=t.title,a=o.length;if(a){var c=kt(t.rtl,t.x,t.width);for(e.x=Lt(t,t._titleAlign),n.textAlign=c.textAlign(t._titleAlign),n.textBaseline="middle",i=t.titleFontSize,r=t.titleSpacing,n.fillStyle=t.titleFontColor,n.font=$.fontString(i,t._titleFontStyle,t._titleFontFamily),s=0;s0&&n.stroke()},draw:function(){var e=this._chart.ctx,t=this._view;if(0!==t.opacity){var n={width:t.width,height:t.height},i={x:t.x,y:t.y},r=Math.abs(t.opacity<.001)?0:t.opacity;this._options.enabled&&(t.title.length||t.beforeBody.length||t.body.length||t.afterBody.length||t.footer.length)&&(e.save(),e.globalAlpha=r,this.drawBackground(i,t,e,n),i.y+=t.yPadding,$.rtl.overrideTextDirection(e,t.textDirection),this.drawTitle(i,t,e),this.drawBody(i,t,e),this.drawFooter(i,t,e),$.rtl.restoreTextDirection(e,t.textDirection),e.restore())}},handleEvent:function(e){var t,n=this,i=n._options;return n._lastActive=n._lastActive||[],"mouseout"===e.type?n._active=[]:(n._active=n._chart.getElementsAtEventForMode(e,i.mode,i),i.reverse&&n._active.reverse()),(t=!$.arrayEquals(n._active,n._lastActive))&&(n._lastActive=n._active,(i.enabled||i.custom)&&(n._eventPosition={x:e.x,y:e.y},n.update(!0),n.pivot())),t}});Et.positioners=Dt;var At=$.valueOrDefault;function It(){return $.merge(Object.create(null),[].slice.call(arguments),{merger:function(e,t,n,i){if("xAxes"===e||"yAxes"===e){var r,s,o,a=n[e].length;for(t[e]||(t[e]=[]),r=0;r=t[e].length&&t[e].push({}),$.merge(t[e][r],!t[e][r].type||o.type&&o.type!==t[e][r].type?[Mt.getScaleDefaults(s),o]:o)}else $._merger(e,t,n,i)}})}function Pt(){return $.merge(Object.create(null),[].slice.call(arguments),{merger:function(e,t,n,i){var r=t[e]||Object.create(null),s=n[e];"scales"===e?t[e]=It(r,s):"scale"===e?t[e]=$.merge(r,[Mt.getScaleDefaults(s.type),s]):$._merger(e,t,n,i)}})}function jt(e){var t=e.options;$.each(e.scales,(function(t){ct.removeBox(e,t)})),t=Pt(j.global,j[e.config.type],t),e.options=e.config.options=t,e.ensureScalesHaveIDs(),e.buildOrUpdateScales(),e.tooltip._options=t.tooltips,e.tooltip.initialize()}function Nt(e,t,n){var i,r=function(e){return e.id===i};do{i=t+n++}while($.findIndex(e,r)>=0);return i}function Ft(e){return"top"===e||"bottom"===e}function Yt(e,t){return function(n,i){return n[e]===i[e]?n[t]-i[t]:n[e]-i[e]}}j._set("global",{elements:{},events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,maintainAspectRatio:!0,responsive:!0,responsiveAnimationDuration:0});var zt=function(e,t){return this.construct(e,t),this};$.extend(zt.prototype,{construct:function(e,t){var n=this;t=function(e){var t=(e=e||Object.create(null)).data=e.data||{};return t.datasets=t.datasets||[],t.labels=t.labels||[],e.options=Pt(j.global,j[e.type],e.options||{}),e}(t);var i=wt.acquireContext(e,t),r=i&&i.canvas,s=r&&r.height,o=r&&r.width;n.id=$.uid(),n.ctx=i,n.canvas=r,n.config=t,n.width=o,n.height=s,n.aspectRatio=s?o/s:null,n.options=t.options,n._bufferedRender=!1,n._layers=[],n.chart=n,n.controller=n,zt.instances[n.id]=n,Object.defineProperty(n,"data",{get:function(){return n.config.data},set:function(e){n.config.data=e}}),i&&r?(n.initialize(),n.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var e=this;return St.notify(e,"beforeInit"),$.retinaScale(e,e.options.devicePixelRatio),e.bindEvents(),e.options.responsive&&e.resize(!0),e.initToolTip(),St.notify(e,"afterInit"),e},clear:function(){return $.canvas.clear(this),this},stop:function(){return J.cancelAnimation(this),this},resize:function(e){var t=this,n=t.options,i=t.canvas,r=n.maintainAspectRatio&&t.aspectRatio||null,s=Math.max(0,Math.floor($.getMaximumWidth(i))),o=Math.max(0,Math.floor(r?s/r:$.getMaximumHeight(i)));if((t.width!==s||t.height!==o)&&(i.width=t.width=s,i.height=t.height=o,i.style.width=s+"px",i.style.height=o+"px",$.retinaScale(t,n.devicePixelRatio),!e)){var a={width:s,height:o};St.notify(t,"resize",[a]),n.onResize&&n.onResize(t,a),t.stop(),t.update({duration:n.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var e=this.options,t=e.scales||{},n=e.scale;$.each(t.xAxes,(function(e,n){e.id||(e.id=Nt(t.xAxes,"x-axis-",n))})),$.each(t.yAxes,(function(e,n){e.id||(e.id=Nt(t.yAxes,"y-axis-",n))})),n&&(n.id=n.id||"scale")},buildOrUpdateScales:function(){var e=this,t=e.options,n=e.scales||{},i=[],r=Object.keys(n).reduce((function(e,t){return e[t]=!1,e}),{});t.scales&&(i=i.concat((t.scales.xAxes||[]).map((function(e){return{options:e,dtype:"category",dposition:"bottom"}})),(t.scales.yAxes||[]).map((function(e){return{options:e,dtype:"linear",dposition:"left"}})))),t.scale&&i.push({options:t.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),$.each(i,(function(t){var i=t.options,s=i.id,o=At(i.type,t.dtype);Ft(i.position)!==Ft(t.dposition)&&(i.position=t.dposition),r[s]=!0;var a=null;if(s in n&&n[s].type===o)(a=n[s]).options=i,a.ctx=e.ctx,a.chart=e;else{var c=Mt.getScaleConstructor(o);if(!c)return;a=new c({id:s,type:o,options:i,ctx:e.ctx,chart:e}),n[a.id]=a}a.mergeTicksOptions(),t.isDefault&&(e.scale=a)})),$.each(r,(function(e,t){e||delete n[t]})),e.scales=n,Mt.addScalesToLayout(this)},buildOrUpdateControllers:function(){var e,t,n=this,i=[],r=n.data.datasets;for(e=0,t=r.length;e=0;--n)i.drawDataset(t[n],e);St.notify(i,"afterDatasetsDraw",[e])}},drawDataset:function(e,t){var n={meta:e,index:e.index,easingValue:t};!1!==St.notify(this,"beforeDatasetDraw",[n])&&(e.controller.draw(t),St.notify(this,"afterDatasetDraw",[n]))},_drawTooltip:function(e){var t=this,n=t.tooltip,i={tooltip:n,easingValue:e};!1!==St.notify(t,"beforeTooltipDraw",[i])&&(n.draw(),St.notify(t,"afterTooltipDraw",[i]))},getElementAtEvent:function(e){return Ze.modes.single(this,e)},getElementsAtEvent:function(e){return Ze.modes.label(this,e,{intersect:!0})},getElementsAtXAxis:function(e){return Ze.modes["x-axis"](this,e,{intersect:!0})},getElementsAtEventForMode:function(e,t,n){var i=Ze.modes[t];return"function"==typeof i?i(this,e,n):[]},getDatasetAtEvent:function(e){return Ze.modes.dataset(this,e,{intersect:!0})},getDatasetMeta:function(e){var t=this,n=t.data.datasets[e];n._meta||(n._meta={});var i=n._meta[t.id];return i||(i=n._meta[t.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:n.order||0,index:e}),i},getVisibleDatasetCount:function(){for(var e=0,t=0,n=this.data.datasets.length;t3?n[2]-n[1]:n[1]-n[0];Math.abs(i)>1&&e!==Math.floor(e)&&(i=e-Math.floor(e));var r=$.log10(Math.abs(i)),s="";if(0!==e)if(Math.max(Math.abs(n[0]),Math.abs(n[n.length-1]))<1e-4){var o=$.log10(Math.abs(e)),a=Math.floor(o)-Math.floor(r);a=Math.max(Math.min(a,20),0),s=e.toExponential(a)}else{var c=-1*Math.floor(r);c=Math.max(Math.min(c,20),0),s=e.toFixed(c)}else s="0";return s},logarithmic:function(e,t,n){var i=e/Math.pow(10,Math.floor($.log10(e)));return 0===e?"0":1===i||2===i||5===i||0===t||t===n.length-1?e.toExponential():""}}},Ut=$.isArray,qt=$.isNullOrUndef,Gt=$.valueOrDefault,Jt=$.valueAtIndexOrDefault;function Qt(e,t,n){var i,r=e.getTicks().length,s=Math.min(t,r-1),o=e.getPixelForTick(s),a=e._startPixel,c=e._endPixel,l=1e-6;if(!(n&&(i=1===r?Math.max(o-a,c-o):0===t?(e.getPixelForTick(1)-o)/2:(o-e.getPixelForTick(s-1))/2,(o+=sc+l)))return o}function Kt(e){return e.drawTicks?e.tickMarkLength:0}function Zt(e){var t,n;return e.display?(t=$.options._parseFont(e),n=$.options.toPadding(e.padding),t.lineHeight+n.height):0}function Xt(e,t){return $.extend($.options._parseFont({fontFamily:Gt(t.fontFamily,e.fontFamily),fontSize:Gt(t.fontSize,e.fontSize),fontStyle:Gt(t.fontStyle,e.fontStyle),lineHeight:Gt(t.lineHeight,e.lineHeight)}),{color:$.options.resolve([t.fontColor,e.fontColor,j.global.defaultFontColor])})}function en(e){var t=Xt(e,e.minor);return{minor:t,major:e.major.enabled?Xt(e,e.major):t}}function tn(e){var t,n,i,r=[];for(n=0,i=e.length;n=h||u<=1||!a.isHorizontal()?a.labelRotation=d:(t=(e=a._getLabelSizes()).widest.width,n=e.highest.height-e.highest.offset,i=Math.min(a.maxWidth,a.chart.width-t),t+6>(r=c.offset?a.maxWidth/u:i/(u-1))&&(r=i/(u-(c.offset?.5:1)),s=a.maxHeight-Kt(c.gridLines)-l.padding-Zt(c.scaleLabel),o=Math.sqrt(t*t+n*n),f=$.toDegrees(Math.min(Math.asin(Math.min((e.highest.height+6)/r,1)),Math.asin(Math.min(s/o,1))-Math.asin(n/o))),f=Math.max(d,Math.min(h,f))),a.labelRotation=f)},afterCalculateTickRotation:function(){$.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){$.callback(this.options.beforeFit,[this])},fit:function(){var e=this,t=e.minSize={width:0,height:0},n=e.chart,i=e.options,r=i.ticks,s=i.scaleLabel,o=i.gridLines,a=e._isVisible(),c="bottom"===i.position,l=e.isHorizontal();if(l?t.width=e.maxWidth:a&&(t.width=Kt(o)+Zt(s)),l?a&&(t.height=Kt(o)+Zt(s)):t.height=e.maxHeight,r.display&&a){var u=en(r),d=e._getLabelSizes(),h=d.first,f=d.last,p=d.widest,m=d.highest,b=.4*u.minor.lineHeight,g=r.padding;if(l){var _=0!==e.labelRotation,y=$.toRadians(e.labelRotation),v=Math.cos(y),w=Math.sin(y);t.height=Math.min(e.maxHeight,t.height+(w*p.width+v*(m.height-(_?m.offset:0))+(_?0:b))+g);var S,M,x=e.getPixelForTick(0)-e.left,k=e.right-e.getPixelForTick(e.getTicks().length-1);_?(S=c?v*h.width+w*h.offset:w*(h.height-h.offset),M=c?w*(f.height-f.offset):v*f.width+w*f.offset):(S=h.width/2,M=f.width/2),e.paddingLeft=Math.max((S-x)*e.width/(e.width-x),0)+3,e.paddingRight=Math.max((M-k)*e.width/(e.width-k),0)+3}else t.width=Math.min(e.maxWidth,t.width+(r.mirror?0:p.width+g+b)),e.paddingTop=h.height/2,e.paddingBottom=f.height/2}e.handleMargins(),l?(e.width=e._length=n.width-e.margins.left-e.margins.right,e.height=t.height):(e.width=t.width,e.height=e._length=n.height-e.margins.top-e.margins.bottom)},handleMargins:function(){var e=this;e.margins&&(e.margins.left=Math.max(e.paddingLeft,e.margins.left),e.margins.top=Math.max(e.paddingTop,e.margins.top),e.margins.right=Math.max(e.paddingRight,e.margins.right),e.margins.bottom=Math.max(e.paddingBottom,e.margins.bottom))},afterFit:function(){$.callback(this.options.afterFit,[this])},isHorizontal:function(){var e=this.options.position;return"top"===e||"bottom"===e},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(e){if(qt(e))return NaN;if(("number"==typeof e||e instanceof Number)&&!isFinite(e))return NaN;if(e)if(this.isHorizontal()){if(void 0!==e.x)return this.getRightValue(e.x)}else if(void 0!==e.y)return this.getRightValue(e.y);return e},_convertTicksToLabels:function(e){var t,n,i,r=this;for(r.ticks=e.map((function(e){return e.value})),r.beforeTickToLabelConversion(),t=r.convertTicksToLabels(e)||r.ticks,r.afterTickToLabelConversion(),n=0,i=e.length;nt){for(n=0;ni-1?null:t.getPixelForDecimal(e*r+(n?r/2:0))},getPixelForDecimal:function(e){var t=this;return t._reversePixels&&(e=1-e),t._startPixel+e*t._length},getDecimalForPixel:function(e){var t=(e-this._startPixel)/this._length;return this._reversePixels?1-t:t},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var e=this,t=e.min,n=e.max;return e.beginAtZero?0:t<0&&n<0?n:t>0&&n>0?t:0},_autoSkip:function(e){var t,n,i,r,s=this,o=s.options.ticks,a=o.maxTicksLimit||s._length/s._tickSize()+1,c=o.major.enabled?function(e){var t,n,i=[];for(t=0,n=e.length;ta)return function(e,t,n){var i,r,s=0,o=t[0];for(n=Math.ceil(n),i=0;il)return s;return Math.max(l,1)}(c,e,0,a),l>0){for(t=0,n=l-1;t1?(d-u)/(l-1):null)?0:u-r,u),nn(e,i,d,$.isNullOrUndef(r)?e.length:d+r),tn(e)}return nn(e,i),tn(e)},_tickSize:function(){var e=this,t=e.options.ticks,n=$.toRadians(e.labelRotation),i=Math.abs(Math.cos(n)),r=Math.abs(Math.sin(n)),s=e._getLabelSizes(),o=t.autoSkipPadding||0,a=s?s.widest.width+o:0,c=s?s.highest.height+o:0;return e.isHorizontal()?c*i>a*r?a/i:c/r:c*r=0&&(o=e),void 0!==s&&(e=n.indexOf(s))>=0&&(a=e),t.minIndex=o,t.maxIndex=a,t.min=n[o],t.max=n[a]},buildTicks:function(){var e=this,t=e._getLabels(),n=e.minIndex,i=e.maxIndex;e.ticks=0===n&&i===t.length-1?t:t.slice(n,i+1)},getLabelForIndex:function(e,t){var n=this,i=n.chart;return i.getDatasetMeta(t).controller._getValueScaleId()===n.id?n.getRightValue(i.data.datasets[t].data[e]):n._getLabels()[e]},_configure:function(){var e=this,t=e.options.offset,n=e.ticks;sn.prototype._configure.call(e),e.isHorizontal()||(e._reversePixels=!e._reversePixels),n&&(e._startValue=e.minIndex-(t?.5:0),e._valueRange=Math.max(n.length-(t?0:1),1))},getPixelForValue:function(e,t,n){var i,r,s,o=this;return on(t)||on(n)||(e=o.chart.data.datasets[n].data[t]),on(e)||(i=o.isHorizontal()?e.x:e.y),(void 0!==i||void 0!==e&&isNaN(t))&&(r=o._getLabels(),e=$.valueOrDefault(i,e),t=-1!==(s=r.indexOf(e))?s:t,isNaN(t)&&(t=e)),o.getPixelForDecimal((t-o._startValue)/o._valueRange)},getPixelForTick:function(e){var t=this.ticks;return e<0||e>t.length-1?null:this.getPixelForValue(t[e],e+this.minIndex)},getValueForPixel:function(e){var t=this,n=Math.round(t._startValue+t.getDecimalForPixel(e)*t._valueRange);return Math.min(Math.max(n,0),t.ticks.length-1)},getBasePixel:function(){return this.bottom}});an._defaults={position:"bottom"};var cn=$.isNullOrUndef,ln=sn.extend({getRightValue:function(e){return"string"==typeof e?+e:sn.prototype.getRightValue.call(this,e)},handleTickRangeOptions:function(){var e=this,t=e.options.ticks;if(t.beginAtZero){var n=$.sign(e.min),i=$.sign(e.max);n<0&&i<0?e.max=0:n>0&&i>0&&(e.min=0)}var r=void 0!==t.min||void 0!==t.suggestedMin,s=void 0!==t.max||void 0!==t.suggestedMax;void 0!==t.min?e.min=t.min:void 0!==t.suggestedMin&&(e.min=null===e.min?t.suggestedMin:Math.min(e.min,t.suggestedMin)),void 0!==t.max?e.max=t.max:void 0!==t.suggestedMax&&(e.max=null===e.max?t.suggestedMax:Math.max(e.max,t.suggestedMax)),r!==s&&e.min>=e.max&&(r?e.max=e.min+1:e.min=e.max-1),e.min===e.max&&(e.max++,t.beginAtZero||e.min--)},getTickLimit:function(){var e,t=this,n=t.options.ticks,i=n.stepSize,r=n.maxTicksLimit;return i?e=Math.ceil(t.max/i)-Math.floor(t.min/i)+1:(e=t._computeTickLimit(),r=r||11),r&&(e=Math.min(r,e)),e},_computeTickLimit:function(){return Number.POSITIVE_INFINITY},handleDirectionalChanges:$.noop,buildTicks:function(){var e=this,t=e.options.ticks,n=e.getTickLimit(),i={maxTicks:n=Math.max(2,n),min:t.min,max:t.max,precision:t.precision,stepSize:$.valueOrDefault(t.fixedStepSize,t.stepSize)},r=e.ticks=function(e,t){var n,i,r,s,o=[],a=e.stepSize,c=a||1,l=e.maxTicks-1,u=e.min,d=e.max,h=e.precision,f=t.min,p=t.max,m=$.niceNum((p-f)/l/c)*c;if(m<1e-14&&cn(u)&&cn(d))return[f,p];(s=Math.ceil(p/m)-Math.floor(f/m))>l&&(m=$.niceNum(s*m/l/c)*c),a||cn(h)?n=Math.pow(10,$._decimalPlaces(m)):(n=Math.pow(10,h),m=Math.ceil(m*n)/n),i=Math.floor(f/m)*m,r=Math.ceil(p/m)*m,a&&(!cn(u)&&$.almostWhole(u/m,m/1e3)&&(i=u),!cn(d)&&$.almostWhole(d/m,m/1e3)&&(r=d)),s=$.almostEquals(s=(r-i)/m,Math.round(s),m/1e3)?Math.round(s):Math.ceil(s),i=Math.round(i*n)/n,r=Math.round(r*n)/n,o.push(cn(u)?i:u);for(var b=1;bt.length-1?null:this.getPixelForValue(t[e])}});fn._defaults=un;var pn=$.valueOrDefault,mn=$.math.log10,bn={position:"left",ticks:{callback:Bt.formatters.logarithmic}};function gn(e,t){return $.isFinite(e)&&e>=0?e:t}var _n=sn.extend({determineDataLimits:function(){var e,t,n,i,r,s,o=this,a=o.options,c=o.chart,l=c.data.datasets,u=o.isHorizontal();function d(e){return u?e.xAxisID===o.id:e.yAxisID===o.id}o.min=Number.POSITIVE_INFINITY,o.max=Number.NEGATIVE_INFINITY,o.minNotZero=Number.POSITIVE_INFINITY;var h=a.stacked;if(void 0===h)for(e=0;e0){var t=$.min(e),n=$.max(e);o.min=Math.min(o.min,t),o.max=Math.max(o.max,n)}}))}else for(e=0;e0?e.min:e.max<1?Math.pow(10,Math.floor(mn(e.max))):1)},buildTicks:function(){var e=this,t=e.options.ticks,n=!e.isHorizontal(),i={min:gn(t.min),max:gn(t.max)},r=e.ticks=function(e,t){var n,i,r=[],s=pn(e.min,Math.pow(10,Math.floor(mn(t.min)))),o=Math.floor(mn(t.max)),a=Math.ceil(t.max/Math.pow(10,o));0===s?(n=Math.floor(mn(t.minNotZero)),i=Math.floor(t.minNotZero/Math.pow(10,n)),r.push(s),s=i*Math.pow(10,n)):(n=Math.floor(mn(s)),i=Math.floor(s/Math.pow(10,n)));var c=n<0?Math.pow(10,Math.abs(n)):1;do{r.push(s),10==++i&&(i=1,c=++n>=0?1:c),s=Math.round(i*Math.pow(10,n)*c)/c}while(nt.length-1?null:this.getPixelForValue(t[e])},_getFirstTickValue:function(e){var t=Math.floor(mn(e));return Math.floor(e/Math.pow(10,t))*Math.pow(10,t)},_configure:function(){var e=this,t=e.min,n=0;sn.prototype._configure.call(e),0===t&&(t=e._getFirstTickValue(e.minNotZero),n=pn(e.options.ticks.fontSize,j.global.defaultFontSize)/e._length),e._startValue=mn(t),e._valueOffset=n,e._valueRange=(mn(e.max)-mn(t))/(1-n)},getPixelForValue:function(e){var t=this,n=0;return(e=+t.getRightValue(e))>t.min&&e>0&&(n=(mn(e)-t._startValue)/t._valueRange+t._valueOffset),t.getPixelForDecimal(n)},getValueForPixel:function(e){var t=this,n=t.getDecimalForPixel(e);return 0===n&&0===t.min?0:Math.pow(10,t._startValue+(n-t._valueOffset)*t._valueRange)}});_n._defaults=bn;var yn=$.valueOrDefault,vn=$.valueAtIndexOrDefault,wn=$.options.resolve,Sn={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0,0,0,0.1)",lineWidth:1,borderDash:[],borderDashOffset:0},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:Bt.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(e){return e}}};function Mn(e){var t=e.ticks;return t.display&&e.display?yn(t.fontSize,j.global.defaultFontSize)+2*t.backdropPaddingY:0}function xn(e,t,n,i,r){return e===i||e===r?{start:t-n/2,end:t+n/2}:er?{start:t-n,end:t}:{start:t,end:t+n}}function kn(e){return 0===e||180===e?"center":e<180?"left":"right"}function Dn(e,t,n,i){var r,s,o=n.y+i/2;if($.isArray(t))for(r=0,s=t.length;r270||e<90)&&(n.y-=t.h)}function Cn(e){return $.isNumber(e)?e:0}var On=ln.extend({setDimensions:function(){var e=this;e.width=e.maxWidth,e.height=e.maxHeight,e.paddingTop=Mn(e.options)/2,e.xCenter=Math.floor(e.width/2),e.yCenter=Math.floor((e.height-e.paddingTop)/2),e.drawingArea=Math.min(e.height-e.paddingTop,e.width)/2},determineDataLimits:function(){var e=this,t=e.chart,n=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;$.each(t.data.datasets,(function(r,s){if(t.isDatasetVisible(s)){var o=t.getDatasetMeta(s);$.each(r.data,(function(t,r){var s=+e.getRightValue(t);isNaN(s)||o.data[r].hidden||(n=Math.min(s,n),i=Math.max(s,i))}))}})),e.min=n===Number.POSITIVE_INFINITY?0:n,e.max=i===Number.NEGATIVE_INFINITY?0:i,e.handleTickRangeOptions()},_computeTickLimit:function(){return Math.ceil(this.drawingArea/Mn(this.options))},convertTicksToLabels:function(){var e=this;ln.prototype.convertTicksToLabels.call(e),e.pointLabels=e.chart.data.labels.map((function(){var t=$.callback(e.options.pointLabels.callback,arguments,e);return t||0===t?t:""}))},getLabelForIndex:function(e,t){return+this.getRightValue(this.chart.data.datasets[t].data[e])},fit:function(){var e=this,t=e.options;t.display&&t.pointLabels.display?function(e){var t,n,i,r=$.options._parseFont(e.options.pointLabels),s={l:0,r:e.width,t:0,b:e.height-e.paddingTop},o={};e.ctx.font=r.string,e._pointLabelSizes=[];var a,c,l,u=e.chart.data.labels.length;for(t=0;ts.r&&(s.r=f.end,o.r=d),p.starts.b&&(s.b=p.end,o.b=d)}e.setReductions(e.drawingArea,s,o)}(e):e.setCenterPoint(0,0,0,0)},setReductions:function(e,t,n){var i=this,r=t.l/Math.sin(n.l),s=Math.max(t.r-i.width,0)/Math.sin(n.r),o=-t.t/Math.cos(n.t),a=-Math.max(t.b-(i.height-i.paddingTop),0)/Math.cos(n.b);r=Cn(r),s=Cn(s),o=Cn(o),a=Cn(a),i.drawingArea=Math.min(Math.floor(e-(r+s)/2),Math.floor(e-(o+a)/2)),i.setCenterPoint(r,s,o,a)},setCenterPoint:function(e,t,n,i){var r=this,s=n+r.drawingArea,o=r.height-r.paddingTop-i-r.drawingArea;r.xCenter=Math.floor((e+r.drawingArea+(r.width-t-r.drawingArea))/2+r.left),r.yCenter=Math.floor((s+o)/2+r.top+r.paddingTop)},getIndexAngle:function(e){var t=this.chart,n=(e*(360/t.data.labels.length)+((t.options||{}).startAngle||0))%360;return(n<0?n+360:n)*Math.PI*2/360},getDistanceFromCenterForValue:function(e){var t=this;if($.isNullOrUndef(e))return NaN;var n=t.drawingArea/(t.max-t.min);return t.options.ticks.reverse?(t.max-e)*n:(e-t.min)*n},getPointPosition:function(e,t){var n=this,i=n.getIndexAngle(e)-Math.PI/2;return{x:Math.cos(i)*t+n.xCenter,y:Math.sin(i)*t+n.yCenter}},getPointPositionForValue:function(e,t){return this.getPointPosition(e,this.getDistanceFromCenterForValue(t))},getBasePosition:function(e){var t=this,n=t.min,i=t.max;return t.getPointPositionForValue(e||0,t.beginAtZero?0:n<0&&i<0?i:n>0&&i>0?n:0)},_drawGrid:function(){var e,t,n,i=this,r=i.ctx,s=i.options,o=s.gridLines,a=s.angleLines,c=yn(a.lineWidth,o.lineWidth),l=yn(a.color,o.color);if(s.pointLabels.display&&function(e){var t=e.ctx,n=e.options,i=n.pointLabels,r=Mn(n),s=e.getDistanceFromCenterForValue(n.ticks.reverse?e.min:e.max),o=$.options._parseFont(i);t.save(),t.font=o.string,t.textBaseline="middle";for(var a=e.chart.data.labels.length-1;a>=0;a--){var c=e.getPointPosition(a,s+(0===a?r/2:0)+5),l=vn(i.fontColor,a,j.global.defaultFontColor);t.fillStyle=l;var u=e.getIndexAngle(a),d=$.toDegrees(u);t.textAlign=kn(d),Tn(d,e._pointLabelSizes[a],c),Dn(t,e.pointLabels[a],c,o.lineHeight)}t.restore()}(i),o.display&&$.each(i.ticks,(function(e,n){0!==n&&(t=i.getDistanceFromCenterForValue(i.ticksAsNumbers[n]),function(e,t,n,i){var r,s=e.ctx,o=t.circular,a=e.chart.data.labels.length,c=vn(t.color,i-1),l=vn(t.lineWidth,i-1);if((o||a)&&c&&l){if(s.save(),s.strokeStyle=c,s.lineWidth=l,s.setLineDash&&(s.setLineDash(t.borderDash||[]),s.lineDashOffset=t.borderDashOffset||0),s.beginPath(),o)s.arc(e.xCenter,e.yCenter,n,0,2*Math.PI);else{r=e.getPointPosition(0,n),s.moveTo(r.x,r.y);for(var u=1;u=0;e--)t=i.getDistanceFromCenterForValue(s.ticks.reverse?i.min:i.max),n=i.getPointPosition(e,t),r.beginPath(),r.moveTo(i.xCenter,i.yCenter),r.lineTo(n.x,n.y),r.stroke();r.restore()}},_drawLabels:function(){var e=this,t=e.ctx,n=e.options.ticks;if(n.display){var i,r,s=e.getIndexAngle(0),o=$.options._parseFont(n),a=yn(n.fontColor,j.global.defaultFontColor);t.save(),t.font=o.string,t.translate(e.xCenter,e.yCenter),t.rotate(s),t.textAlign="center",t.textBaseline="middle",$.each(e.ticks,(function(s,c){(0!==c||n.reverse)&&(i=e.getDistanceFromCenterForValue(e.ticksAsNumbers[c]),n.showLabelBackdrop&&(r=t.measureText(s).width,t.fillStyle=n.backdropColor,t.fillRect(-r/2-n.backdropPaddingX,-i-o.size/2-n.backdropPaddingY,r+2*n.backdropPaddingX,o.size+2*n.backdropPaddingY)),t.fillStyle=a,t.fillText(s,0,-i))})),t.restore()}},_drawTitle:$.noop});On._defaults=Sn;var Ln=$._deprecated,Rn=$.options.resolve,En=$.valueOrDefault,An=Number.MIN_SAFE_INTEGER||-9007199254740991,In=Number.MAX_SAFE_INTEGER||9007199254740991,Pn={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},jn=Object.keys(Pn);function Nn(e,t){return e-t}function Fn(e){return $.valueOrDefault(e.time.min,e.ticks.min)}function Yn(e){return $.valueOrDefault(e.time.max,e.ticks.max)}function zn(e,t,n,i){var r=function(e,t,n){for(var i,r,s,o=0,a=e.length-1;o>=0&&o<=a;){if(s=e[i=o+a>>1],!(r=e[i-1]||null))return{lo:null,hi:s};if(s[t]n))return{lo:r,hi:s};a=i-1}}return{lo:s,hi:null}}(e,t,n),s=r.lo?r.hi?r.lo:e[e.length-2]:e[0],o=r.lo?r.hi?r.hi:e[e.length-1]:e[1],a=o[t]-s[t];return s[i]+(o[i]-s[i])*(a?(n-s[t])/a:0)}function $n(e,t){var n=e._adapter,i=e.options.time,r=i.parser,s=r||i.format,o=t;return"function"==typeof r&&(o=r(o)),$.isFinite(o)||(o="string"==typeof s?n.parse(o,s):n.parse(o)),null!==o?+o:(r||"function"!=typeof s||(o=s(t),$.isFinite(o)||(o=n.parse(o))),o)}function Hn(e,t){if($.isNullOrUndef(t))return null;var n=e.options.time,i=$n(e,e.getRightValue(t));return null===i||n.round&&(i=+e._adapter.startOf(i,n.round)),i}function Wn(e,t,n,i){var r,s,o=jn.length;for(r=jn.indexOf(e);r=0&&(t[s].major=!0);return t}(e,s,o,n):s}var Bn=sn.extend({initialize:function(){this.mergeTicksOptions(),sn.prototype.initialize.call(this)},update:function(){var e=this,t=e.options,n=t.time||(t.time={}),i=e._adapter=new Vt._date(t.adapters.date);return Ln("time scale",n.format,"time.format","time.parser"),Ln("time scale",n.min,"time.min","ticks.min"),Ln("time scale",n.max,"time.max","ticks.max"),$.mergeIf(n.displayFormats,i.formats()),sn.prototype.update.apply(e,arguments)},getRightValue:function(e){return e&&void 0!==e.t&&(e=e.t),sn.prototype.getRightValue.call(this,e)},determineDataLimits:function(){var e,t,n,i,r,s,o,a=this,c=a.chart,l=a._adapter,u=a.options,d=u.time.unit||"day",h=In,f=An,p=[],m=[],b=[],g=a._getLabels();for(e=0,n=g.length;e1?function(e){var t,n,i,r={},s=[];for(t=0,n=e.length;t1e5*l)throw t+" and "+n+" are too far apart with stepSize of "+l+" "+c;for(r=d;r=r&&n<=s&&u.push(n);return i.min=r,i.max=s,i._unit=c.unit||(a.autoSkip?Wn(c.minUnit,i.min,i.max,d):function(e,t,n,i,r){var s,o;for(s=jn.length-1;s>=jn.indexOf(n);s--)if(Pn[o=jn[s]].common&&e._adapter.diff(r,i,o)>=t-1)return o;return jn[n?jn.indexOf(n):0]}(i,u.length,c.minUnit,i.min,i.max)),i._majorUnit=a.major.enabled&&"year"!==i._unit?function(e){for(var t=jn.indexOf(e)+1,n=jn.length;tt&&a=0&&e0?a:1}});Bn._defaults={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};var Un={category:an,linear:fn,logarithmic:_n,radialLinear:On,time:Bn},qn={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};Vt._date.override("function"==typeof e?{_id:"moment",formats:function(){return qn},parse:function(t,n){return"string"==typeof t&&"string"==typeof n?t=e(t,n):t instanceof e||(t=e(t)),t.isValid()?t.valueOf():null},format:function(t,n){return e(t).format(n)},add:function(t,n,i){return e(t).add(n,i).valueOf()},diff:function(t,n,i){return e(t).diff(e(n),i)},startOf:function(t,n,i){return t=e(t),"isoWeek"===n?t.isoWeekday(i).valueOf():t.startOf(n).valueOf()},endOf:function(t,n){return e(t).endOf(n).valueOf()},_create:function(t){return e(t)}}:{}),j._set("global",{plugins:{filler:{propagate:!0}}});var Gn={dataset:function(e){var t=e.fill,n=e.chart,i=n.getDatasetMeta(t),r=i&&n.isDatasetVisible(t)&&i.dataset._children||[],s=r.length||0;return s?function(e,t){return t=n)&&i;switch(s){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return s;default:return!1}}function Qn(e){return(e.el._scale||{}).getPointPositionForValue?function(e){var t,n,i,r,s,o=e.el._scale,a=o.options,c=o.chart.data.labels.length,l=e.fill,u=[];if(!c)return null;for(n=a.ticks.reverse?o.min:o.max,i=o.getPointPositionForValue(0,t=a.ticks.reverse?o.max:o.min),r=0;r0;--s)$.canvas.lineTo(e,n[s],n[s-1],!0);else for(o=n[0].cx,a=n[0].cy,c=Math.sqrt(Math.pow(n[0].x-o,2)+Math.pow(n[0].y-a,2)),s=r-1;s>0;--s)e.arc(o,a,c,n[s].angle,n[s-1].angle,!0)}}function ti(e,t,n,i,r,s){var o,a,c,l,u,d,h,f,p=t.length,m=i.spanGaps,b=[],g=[],_=0,y=0;for(e.beginPath(),o=0,a=p;o=0;--n)(t=c[n].$filler)&&t.visible&&(s=(i=t.el)._children||[],a=(r=i._view).backgroundColor||j.global.defaultColor,(o=t.mapper)&&a&&s.length&&($.canvas.clipArea(l,e.chartArea),ti(l,s,o,r,a,i._loop),$.canvas.unclipArea(l)))}},ii=$.rtl.getRtlAdapter,ri=$.noop,si=$.valueOrDefault;function oi(e,t){return e.usePointStyle&&e.boxWidth>t?t:e.boxWidth}j._set("global",{legend:{display:!0,position:"top",align:"center",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(e,t){var n=t.datasetIndex,i=this.chart,r=i.getDatasetMeta(n);r.hidden=null===r.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(e){var t=e.data.datasets,n=e.options.legend||{},i=n.labels&&n.labels.usePointStyle;return e._getSortedDatasetMetas().map((function(n){var r=n.controller.getStyle(i?0:void 0);return{text:t[n.index].label,fillStyle:r.backgroundColor,hidden:!e.isDatasetVisible(n.index),lineCap:r.borderCapStyle,lineDash:r.borderDash,lineDashOffset:r.borderDashOffset,lineJoin:r.borderJoinStyle,lineWidth:r.borderWidth,strokeStyle:r.borderColor,pointStyle:r.pointStyle,rotation:r.rotation,datasetIndex:n.index}}),this)}}},legendCallback:function(e){var t,n,i,r=document.createElement("ul"),s=e.data.datasets;for(r.setAttribute("class",e.id+"-legend"),t=0,n=s.length;tc.width)&&(d+=o+n.padding,u[u.length-(t>0?0:1)]=0),a[t]={left:0,top:0,width:i,height:o},u[u.length-1]+=i+n.padding})),c.height+=d}else{var h=n.padding,f=e.columnWidths=[],p=e.columnHeights=[],m=n.padding,b=0,g=0;$.each(e.legendItems,(function(e,t){var i=oi(n,o)+o/2+r.measureText(e.text).width;t>0&&g+o+2*h>c.height&&(m+=b+n.padding,f.push(b),p.push(g),b=0,g=0),b=Math.max(b,i),g+=o+h,a[t]={left:0,top:0,width:i,height:o}})),m+=b,f.push(b),p.push(g),c.width+=m}e.width=c.width,e.height=c.height}else e.width=c.width=e.height=c.height=0},afterFit:ri,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var e=this,t=e.options,n=t.labels,i=j.global,r=i.defaultColor,s=i.elements.line,o=e.height,a=e.columnHeights,c=e.width,l=e.lineWidths;if(t.display){var u,d=ii(t.rtl,e.left,e.minSize.width),h=e.ctx,f=si(n.fontColor,i.defaultFontColor),p=$.options._parseFont(n),m=p.size;h.textAlign=d.textAlign("left"),h.textBaseline="middle",h.lineWidth=.5,h.strokeStyle=f,h.fillStyle=f,h.font=p.string;var b=oi(n,m),g=e.legendHitBoxes,_=function(e,i){switch(t.align){case"start":return n.padding;case"end":return e-i;default:return(e-i+n.padding)/2}},y=e.isHorizontal();u=y?{x:e.left+_(c,l[0]),y:e.top+n.padding,line:0}:{x:e.left+n.padding,y:e.top+_(o,a[0]),line:0},$.rtl.overrideTextDirection(e.ctx,t.textDirection);var v=m+n.padding;$.each(e.legendItems,(function(t,i){var f=h.measureText(t.text).width,p=b+m/2+f,w=u.x,S=u.y;d.setWidth(e.minSize.width),y?i>0&&w+p+n.padding>e.left+e.minSize.width&&(S=u.y+=v,u.line++,w=u.x=e.left+_(c,l[u.line])):i>0&&S+v>e.top+e.minSize.height&&(w=u.x=w+e.columnWidths[u.line]+n.padding,u.line++,S=u.y=e.top+_(o,a[u.line]));var M=d.x(w);(function(e,t,i){if(!(isNaN(b)||b<=0)){h.save();var o=si(i.lineWidth,s.borderWidth);if(h.fillStyle=si(i.fillStyle,r),h.lineCap=si(i.lineCap,s.borderCapStyle),h.lineDashOffset=si(i.lineDashOffset,s.borderDashOffset),h.lineJoin=si(i.lineJoin,s.borderJoinStyle),h.lineWidth=o,h.strokeStyle=si(i.strokeStyle,r),h.setLineDash&&h.setLineDash(si(i.lineDash,s.borderDash)),n&&n.usePointStyle){var a=b*Math.SQRT2/2,c=d.xPlus(e,b/2);$.canvas.drawPoint(h,i.pointStyle,a,c,t+m/2,i.rotation)}else h.fillRect(d.leftForLtr(e,b),t,b,m),0!==o&&h.strokeRect(d.leftForLtr(e,b),t,b,m);h.restore()}})(M,S,t),g[i].left=d.leftForLtr(M,g[i].width),g[i].top=S,function(e,t,n,i){var r=m/2,s=d.xPlus(e,b+r),o=t+r;h.fillText(n.text,s,o),n.hidden&&(h.beginPath(),h.lineWidth=2,h.moveTo(s,o),h.lineTo(d.xPlus(s,i),o),h.stroke())}(M,S,t,f),y?u.x+=p+n.padding:u.y+=v})),$.rtl.restoreTextDirection(e.ctx,t.textDirection)}},_getLegendItemAt:function(e,t){var n,i,r,s=this;if(e>=s.left&&e<=s.right&&t>=s.top&&t<=s.bottom)for(r=s.legendHitBoxes,n=0;n=(i=r[n]).left&&e<=i.left+i.width&&t>=i.top&&t<=i.top+i.height)return s.legendItems[n];return null},handleEvent:function(e){var t,n=this,i=n.options,r="mouseup"===e.type?"click":e.type;if("mousemove"===r){if(!i.onHover&&!i.onLeave)return}else{if("click"!==r)return;if(!i.onClick)return}t=n._getLegendItemAt(e.x,e.y),"click"===r?t&&i.onClick&&i.onClick.call(n,e.native,t):(i.onLeave&&t!==n._hoveredItem&&(n._hoveredItem&&i.onLeave.call(n,e.native,n._hoveredItem),n._hoveredItem=t),i.onHover&&t&&i.onHover.call(n,e.native,t))}});function ci(e,t){var n=new ai({ctx:e.ctx,options:t,chart:e});ct.configure(e,n,t),ct.addBox(e,n),e.legend=n}var li={id:"legend",_element:ai,beforeInit:function(e){var t=e.options.legend;t&&ci(e,t)},beforeUpdate:function(e){var t=e.options.legend,n=e.legend;t?($.mergeIf(t,j.global.legend),n?(ct.configure(e,n,t),n.options=t):ci(e,t)):n&&(ct.removeBox(e,n),delete e.legend)},afterEvent:function(e,t){var n=e.legend;n&&n.handleEvent(t)}},ui=$.noop;j._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var di=U.extend({initialize:function(e){$.extend(this,e),this.legendHitBoxes=[]},beforeUpdate:ui,update:function(e,t,n){var i=this;return i.beforeUpdate(),i.maxWidth=e,i.maxHeight=t,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:ui,beforeSetDimensions:ui,setDimensions:function(){var e=this;e.isHorizontal()?(e.width=e.maxWidth,e.left=0,e.right=e.width):(e.height=e.maxHeight,e.top=0,e.bottom=e.height),e.paddingLeft=0,e.paddingTop=0,e.paddingRight=0,e.paddingBottom=0,e.minSize={width:0,height:0}},afterSetDimensions:ui,beforeBuildLabels:ui,buildLabels:ui,afterBuildLabels:ui,beforeFit:ui,fit:function(){var e,t=this,n=t.options,i=t.minSize={},r=t.isHorizontal();n.display?(e=($.isArray(n.text)?n.text.length:1)*$.options._parseFont(n).lineHeight+2*n.padding,t.width=i.width=r?t.maxWidth:e,t.height=i.height=r?e:t.maxHeight):t.width=i.width=t.height=i.height=0},afterFit:ui,isHorizontal:function(){var e=this.options.position;return"top"===e||"bottom"===e},draw:function(){var e=this,t=e.ctx,n=e.options;if(n.display){var i,r,s,o=$.options._parseFont(n),a=o.lineHeight,c=a/2+n.padding,l=0,u=e.top,d=e.left,h=e.bottom,f=e.right;t.fillStyle=$.valueOrDefault(n.fontColor,j.global.defaultFontColor),t.font=o.string,e.isHorizontal()?(r=d+(f-d)/2,s=u+c,i=f-d):(r="left"===n.position?d+c:f-c,s=u+(h-u)/2,i=h-u,l=Math.PI*("left"===n.position?-.5:.5)),t.save(),t.translate(r,s),t.rotate(l),t.textAlign="center",t.textBaseline="middle";var p=n.text;if($.isArray(p))for(var m=0,b=0;b=0;i--){var r=e[i];if(t(r))return r}},$.isNumber=function(e){return!isNaN(parseFloat(e))&&isFinite(e)},$.almostEquals=function(e,t,n){return Math.abs(e-t)=e},$.max=function(e){return e.reduce((function(e,t){return isNaN(t)?e:Math.max(e,t)}),Number.NEGATIVE_INFINITY)},$.min=function(e){return e.reduce((function(e,t){return isNaN(t)?e:Math.min(e,t)}),Number.POSITIVE_INFINITY)},$.sign=Math.sign?function(e){return Math.sign(e)}:function(e){return 0==(e=+e)||isNaN(e)?e:e>0?1:-1},$.toRadians=function(e){return e*(Math.PI/180)},$.toDegrees=function(e){return e*(180/Math.PI)},$._decimalPlaces=function(e){if($.isFinite(e)){for(var t=1,n=0;Math.round(e*t)/t!==e;)t*=10,n++;return n}},$.getAngleFromPoint=function(e,t){var n=t.x-e.x,i=t.y-e.y,r=Math.sqrt(n*n+i*i),s=Math.atan2(i,n);return s<-.5*Math.PI&&(s+=2*Math.PI),{angle:s,distance:r}},$.distanceBetweenPoints=function(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))},$.aliasPixel=function(e){return e%2==0?0:.5},$._alignPixel=function(e,t,n){var i=e.currentDevicePixelRatio,r=n/2;return Math.round((t-r)*i)/i+r},$.splineCurve=function(e,t,n,i){var r=e.skip?t:e,s=t,o=n.skip?t:n,a=Math.sqrt(Math.pow(s.x-r.x,2)+Math.pow(s.y-r.y,2)),c=Math.sqrt(Math.pow(o.x-s.x,2)+Math.pow(o.y-s.y,2)),l=a/(a+c),u=c/(a+c),d=i*(l=isNaN(l)?0:l),h=i*(u=isNaN(u)?0:u);return{previous:{x:s.x-d*(o.x-r.x),y:s.y-d*(o.y-r.y)},next:{x:s.x+h*(o.x-r.x),y:s.y+h*(o.y-r.y)}}},$.EPSILON=Number.EPSILON||1e-14,$.splineCurveMonotone=function(e){var t,n,i,r,s,o,a,c,l,u=(e||[]).map((function(e){return{model:e._model,deltaK:0,mK:0}})),d=u.length;for(t=0;t0?u[t-1]:null,(r=t0?u[t-1]:null)&&!n.model.skip&&(i.model.controlPointPreviousX=i.model.x-(l=(i.model.x-n.model.x)/3),i.model.controlPointPreviousY=i.model.y-l*i.mK),r&&!r.model.skip&&(i.model.controlPointNextX=i.model.x+(l=(r.model.x-i.model.x)/3),i.model.controlPointNextY=i.model.y+l*i.mK))},$.nextItem=function(e,t,n){return n?t>=e.length-1?e[0]:e[t+1]:t>=e.length-1?e[e.length-1]:e[t+1]},$.previousItem=function(e,t,n){return n?t<=0?e[e.length-1]:e[t-1]:t<=0?e[0]:e[t-1]},$.niceNum=function(e,t){var n=Math.floor($.log10(e)),i=e/Math.pow(10,n);return(t?i<1.5?1:i<3?2:i<7?5:10:i<=1?1:i<=2?2:i<=5?5:10)*Math.pow(10,n)},$.requestAnimFrame="undefined"==typeof window?function(e){e()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){return window.setTimeout(e,1e3/60)},$.getRelativePosition=function(e,t){var n,i,r=e.originalEvent||e,s=e.target||e.srcElement,o=s.getBoundingClientRect(),a=r.touches;a&&a.length>0?(n=a[0].clientX,i=a[0].clientY):(n=r.clientX,i=r.clientY);var c=parseFloat($.getStyle(s,"padding-left")),l=parseFloat($.getStyle(s,"padding-top")),u=parseFloat($.getStyle(s,"padding-right")),d=parseFloat($.getStyle(s,"padding-bottom")),h=o.bottom-o.top-l-d;return{x:n=Math.round((n-o.left-c)/(o.right-o.left-c-u)*s.width/t.currentDevicePixelRatio),y:i=Math.round((i-o.top-l)/h*s.height/t.currentDevicePixelRatio)}},$.getConstraintWidth=function(e){return n(e,"max-width","clientWidth")},$.getConstraintHeight=function(e){return n(e,"max-height","clientHeight")},$._calculatePadding=function(e,t,n){return(t=$.getStyle(e,t)).indexOf("%")>-1?n*parseInt(t,10)/100:parseInt(t,10)},$._getParentNode=function(e){var t=e.parentNode;return t&&"[object ShadowRoot]"===t.toString()&&(t=t.host),t},$.getMaximumWidth=function(e){var t=$._getParentNode(e);if(!t)return e.clientWidth;var n=t.clientWidth,i=n-$._calculatePadding(t,"padding-left",n)-$._calculatePadding(t,"padding-right",n),r=$.getConstraintWidth(e);return isNaN(r)?i:Math.min(i,r)},$.getMaximumHeight=function(e){var t=$._getParentNode(e);if(!t)return e.clientHeight;var n=t.clientHeight,i=n-$._calculatePadding(t,"padding-top",n)-$._calculatePadding(t,"padding-bottom",n),r=$.getConstraintHeight(e);return isNaN(r)?i:Math.min(i,r)},$.getStyle=function(e,t){return e.currentStyle?e.currentStyle[t]:document.defaultView.getComputedStyle(e,null).getPropertyValue(t)},$.retinaScale=function(e,t){var n=e.currentDevicePixelRatio=t||"undefined"!=typeof window&&window.devicePixelRatio||1;if(1!==n){var i=e.canvas,r=e.height,s=e.width;i.height=r*n,i.width=s*n,e.ctx.scale(n,n),i.style.height||i.style.width||(i.style.height=r+"px",i.style.width=s+"px")}},$.fontString=function(e,t,n){return t+" "+e+"px "+n},$.longestText=function(e,t,n,i){var r=(i=i||{}).data=i.data||{},s=i.garbageCollect=i.garbageCollect||[];i.font!==t&&(r=i.data={},s=i.garbageCollect=[],i.font=t),e.font=t;var o,a,c,l,u,d=0,h=n.length;for(o=0;on.length){for(o=0;oi&&(i=s),i},$.numberOfLabelLines=function(e){var t=1;return $.each(e,(function(e){$.isArray(e)&&e.length>t&&(t=e.length)})),t},$.color=v?function(e){return e instanceof CanvasGradient&&(e=j.global.defaultColor),v(e)}:function(e){return console.error("Color.js not found!"),e},$.getHoverColor=function(e){return e instanceof CanvasPattern||e instanceof CanvasGradient?e:$.color(e).saturate(.5).darken(.1).rgbString()}}(),$t._adapters=Vt,$t.Animation=G,$t.animationService=J,$t.controllers=Be,$t.DatasetController=ee,$t.defaults=j,$t.Element=U,$t.elements=ge,$t.Interaction=Ze,$t.layouts=ct,$t.platform=wt,$t.plugins=St,$t.Scale=sn,$t.scaleService=Mt,$t.Ticks=Bt,$t.Tooltip=Et,$t.helpers.each(Un,(function(e,t){$t.scaleService.registerScaleType(t,e,e._defaults)})),fi)fi.hasOwnProperty(gi)&&$t.plugins.register(fi[gi]);$t.platform.initialize();var _i=$t;return"undefined"!=typeof window&&(window.Chart=$t),$t.Chart=$t,$t.Legend=fi.legend._element,$t.Title=fi.title._element,$t.pluginService=$t.plugins,$t.PluginBase=$t.Element.extend({}),$t.canvasHelpers=$t.helpers.canvas,$t.layoutService=$t.layouts,$t.LinearScaleBase=ln,$t.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],(function(e){$t[e]=function(t,n){return new $t(t,$t.helpers.merge(n||{},{type:e.charAt(0).toLowerCase()+e.slice(1)}))}})),_i}(function(){try{return n("wd/R")}catch(e){}}())},MuvH:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("8Y7J"),r=n("IheW");let s=(()=>{class e{constructor(e){this.http=e}findValue(e,t){if(e.value)return e.value.find(e=>e.section===t)}getValue(e,t){let n=this.findValue(e,t);if(!n){const i=t.indexOf(".");-1!==i&&(n=this.findValue(e,t.substring(0,i)))}return n||(n=this.findValue(e,"global")),n?n.value:e.default}getConfigData(){return this.http.get("api/cluster_conf/")}get(e){return this.http.get("api/cluster_conf/"+e)}filter(e){return this.http.get("api/cluster_conf/filter?names="+e.join(","))}create(e){return this.http.post("api/cluster_conf/",e)}delete(e,t){return this.http.delete(`api/cluster_conf/${e}?section=${t}`)}bulkCreate(e){return this.http.put("api/cluster_conf/",e)}}return e.\u0275fac=function(t){return new(t||e)(i.dc(r.b))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},Mxhz:function(e,t,n){"use strict";n.d(t,"a",(function(){return c}));var i=n("LRne"),r=n("CqXF"),s=n("JIr8"),o=n("8Y7J"),a=n("IheW");let c=(()=>{class e{constructor(e){this.http=e}list(){return this.http.get("api/user")}delete(e){return this.http.delete("api/user/"+e)}get(e){return this.http.get("api/user/"+e)}create(e){return this.http.post("api/user",e)}update(e){return this.http.put("api/user/"+e.username,e)}changePassword(e,t,n){return this.http.post(`api/user/${e}/change_password`,{old_password:t,new_password:n})}validateUserName(e){return this.get(e).pipe(Object(r.a)(!0),Object(s.a)(e=>(e.preventDefault(),Object(i.a)(!1))))}validatePassword(e,t=null,n=null){return this.http.post("api/user/validate_password",{password:e,username:t,old_password:n})}}return e.\u0275fac=function(t){return new(t||e)(o.dc(a.b))},e.\u0275prov=o.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},"N+g0":function(e,t,n){var i=n("g6v/"),r=n("m/L8"),s=n("glrk"),o=n("33Wh");e.exports=i?Object.defineProperties:function(e,t){s(e);for(var n,i=o(t),a=i.length,c=0;a>c;)r.f(e,n=i[c++],t[n]);return e}},"NC/Y":function(e,t,n){var i=n("0GbY");e.exports=i("navigator","userAgent")||""},NEZu:function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));class i{constructor(e,t,n,i){this.customColors={backgroundColor:void 0,borderColor:void 0},this.checkOffset=!1,this.chartEl=e.nativeElement,this.getStyleLeft=n,this.getStyleTop=i,this.tooltipEl=t.nativeElement}customTooltips(e){if(0===e.opacity)return void(this.tooltipEl.style.opacity=0);if(this.tooltipEl.classList.remove("above","below","no-transform"),this.tooltipEl.classList.add(e.yAlign?e.yAlign:"no-transform"),e.body){const t=e.title||[],n=e.body.map(e=>e.lines);let i="";t.forEach(e=>{i+=""+this.getTitle(e)+""}),i+="",n.forEach((t,n)=>{const r=e.labelColors[n];let s="background:"+(this.customColors.backgroundColor||r.backgroundColor);s+="; border-color:"+(this.customColors.borderColor||r.borderColor),s+="; border-width: 2px",i+=''+this.getBody(t)+""}),i+="",this.tooltipEl.querySelector("table").innerHTML=i}const t=this.chartEl.offsetTop,n=this.chartEl.offsetLeft;if(this.checkOffset){const t=e.width/2;this.tooltipEl.classList.remove("transform-left"),this.tooltipEl.classList.remove("transform-right"),e.caretX-t<0?this.tooltipEl.classList.add("transform-left"):e.caretX+t>this.chartEl.width&&this.tooltipEl.classList.add("transform-right")}this.tooltipEl.style.left=this.getStyleLeft(e,n),this.tooltipEl.style.top=this.getStyleTop(e,t),this.tooltipEl.style.opacity=1,this.tooltipEl.style.fontFamily=e._fontFamily,this.tooltipEl.style.fontSize=e.fontSize,this.tooltipEl.style.fontStyle=e._fontStyle,this.tooltipEl.style.padding=e.yPadding+"px "+e.xPadding+"px"}getBody(e){return e}getTitle(e){return e}}},NJ4a:function(e,t,n){"use strict";function i(e){setTimeout(()=>{throw e},0)}n.d(t,"a",(function(){return i}))},NJ9Y:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("sVev"),r=n("pLZG"),s=n("BFxc"),o=n("XDbj"),a=n("xbPD"),c=n("SpAZ");function l(e,t){const n=arguments.length>=2;return l=>l.pipe(e?Object(r.a)((t,n)=>e(t,n,l)):c.a,Object(s.a)(1),n?Object(a.a)(t):Object(o.a)(()=>new i.a))}},NaFW:function(e,t,n){var i=n("9d/t"),r=n("P4y1"),s=n("tiKp")("iterator");e.exports=function(e){if(null!=e)return e[s]||e["@@iterator"]||r[i(e)]}},NwgZ:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("8Y7J"),r=n("s7LF");let s=(()=>{class e{constructor(){this.validSubmit=new i.o}onSubmit(){this.markAsTouchedAndDirty(this.formGroup),this.formGroup.valid&&this.validSubmit.emit(this.formGroup.value)}markAsTouchedAndDirty(e){e instanceof r.j?Object.keys(e.controls).forEach(t=>this.markAsTouchedAndDirty(e.controls[t])):e instanceof r.e?e.controls.forEach(e=>this.markAsTouchedAndDirty(e)):e instanceof r.h&&e.enabled&&(e.markAsDirty(),e.markAsTouched(),e.updateValueAndValidity())}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=i.Hb({type:e,selectors:[["","formGroup",""]],hostBindings:function(e,t){1&e&&i.gc("submit",(function(){return t.onSubmit()}))},inputs:{formGroup:"formGroup"},outputs:{validSubmit:"validSubmit"}}),e})()},O741:function(e,t,n){var i=n("hh1v");e.exports=function(e){if(!i(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},OIYi:function(e,t,n){!function(e){"use strict";e.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}})}(n("wd/R"))},OLbh:function(e,t,n){"use strict";n.d(t,"a",(function(){return f}));var i=n("s7LF"),r=n("8Y7J"),s=n("G0yt"),o=n("ajRT"),a=n("SVse"),c=n("NwgZ"),l=n("6+kj");function u(e,t){1&e&&(r.Sb(0,"span",11),r.Nb(1,"i",12),r.Rb())}function d(e,t){1&e&&r.Ob(0)}function h(e,t){if(1&e&&(r.Sb(0,"p"),r.Oc(1),r.Rb()),2&e){const e=r.ic();r.yb(1),r.Qc(" ",e.description," ")}}let f=(()=>{class e{constructor(e){this.activeModal=e,this.warning=!1,this.showSubmit=!0,this.boundCancel=this.cancel.bind(this),this.canceled=!1,this.confirmationForm=new i.j({})}ngOnInit(){if(this.bodyContext=this.bodyContext||{},this.bodyContext.$implicit=this.bodyData,!this.onSubmit)throw new Error("No submit action defined");if(!this.buttonText)throw new Error("No action name defined");if(!this.titleText)throw new Error("No title defined");if(!this.bodyTpl&&!this.description)throw new Error("No description defined")}ngOnDestroy(){this.onCancel&&this.canceled&&this.onCancel()}cancel(){this.canceled=!0,this.activeModal.close()}stopLoadingSpinner(){this.confirmationForm.setErrors({cdSubmitButton:!0})}}return e.\u0275fac=function(t){return new(t||e)(r.Mb(s.a))},e.\u0275cmp=r.Gb({type:e,selectors:[["cd-confirmation-modal"]],decls:12,vars:9,consts:[[3,"hide"],[1,"modal-title"],["class","text-warning",4,"ngIf"],[1,"modal-content"],["name","confirmationForm","novalidate","",3,"formGroup"],["formDir","ngForm"],[1,"modal-body"],[4,"ngTemplateOutlet","ngTemplateOutletContext"],[4,"ngIf"],[1,"modal-footer"],[3,"form","submitText","showSubmit","submitActionEvent","backActionEvent"],[1,"text-warning"],[1,"fa","fa-exclamation-triangle","fa-1x"]],template:function(e,t){1&e&&(r.Sb(0,"cd-modal",0),r.gc("hide",(function(){return t.cancel()})),r.Qb(1,1),r.Mc(2,u,2,0,"span",2),r.Oc(3),r.Pb(),r.Qb(4,3),r.Sb(5,"form",4,5),r.Sb(7,"div",6),r.Mc(8,d,1,0,"ng-container",7),r.Mc(9,h,2,1,"p",8),r.Rb(),r.Sb(10,"div",9),r.Sb(11,"cd-form-button-panel",10),r.gc("submitActionEvent",(function(){return t.onSubmit(t.confirmationForm.value)}))("backActionEvent",(function(){return t.boundCancel()})),r.Rb(),r.Rb(),r.Rb(),r.Pb(),r.Rb()),2&e&&(r.yb(2),r.pc("ngIf",t.warning),r.yb(1),r.Pc(t.titleText),r.yb(2),r.pc("formGroup",t.confirmationForm),r.yb(3),r.pc("ngTemplateOutlet",t.bodyTpl)("ngTemplateOutletContext",t.bodyContext),r.yb(1),r.pc("ngIf",t.description),r.yb(2),r.pc("form",t.confirmationForm)("submitText",t.buttonText)("showSubmit",t.showSubmit))},directives:[o.a,a.r,i.C,i.r,i.k,c.a,a.w,l.a],styles:[""]}),e})()},Oaa7:function(e,t,n){!function(e){"use strict";e.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(n("wd/R"))},Ob0Z:function(e,t,n){!function(e){"use strict";var t={1:"\u0967",2:"\u0968",3:"\u0969",4:"\u096a",5:"\u096b",6:"\u096c",7:"\u096d",8:"\u096e",9:"\u096f",0:"\u0966"},n={"\u0967":"1","\u0968":"2","\u0969":"3","\u096a":"4","\u096b":"5","\u096c":"6","\u096d":"7","\u096e":"8","\u096f":"9","\u0966":"0"};function i(e,t,n,i){var r="";if(t)switch(n){case"s":r="\u0915\u093e\u0939\u0940 \u0938\u0947\u0915\u0902\u0926";break;case"ss":r="%d \u0938\u0947\u0915\u0902\u0926";break;case"m":r="\u090f\u0915 \u092e\u093f\u0928\u093f\u091f";break;case"mm":r="%d \u092e\u093f\u0928\u093f\u091f\u0947";break;case"h":r="\u090f\u0915 \u0924\u093e\u0938";break;case"hh":r="%d \u0924\u093e\u0938";break;case"d":r="\u090f\u0915 \u0926\u093f\u0935\u0938";break;case"dd":r="%d \u0926\u093f\u0935\u0938";break;case"M":r="\u090f\u0915 \u092e\u0939\u093f\u0928\u093e";break;case"MM":r="%d \u092e\u0939\u093f\u0928\u0947";break;case"y":r="\u090f\u0915 \u0935\u0930\u094d\u0937";break;case"yy":r="%d \u0935\u0930\u094d\u0937\u0947"}else switch(n){case"s":r="\u0915\u093e\u0939\u0940 \u0938\u0947\u0915\u0902\u0926\u093e\u0902";break;case"ss":r="%d \u0938\u0947\u0915\u0902\u0926\u093e\u0902";break;case"m":r="\u090f\u0915\u093e \u092e\u093f\u0928\u093f\u091f\u093e";break;case"mm":r="%d \u092e\u093f\u0928\u093f\u091f\u093e\u0902";break;case"h":r="\u090f\u0915\u093e \u0924\u093e\u0938\u093e";break;case"hh":r="%d \u0924\u093e\u0938\u093e\u0902";break;case"d":r="\u090f\u0915\u093e \u0926\u093f\u0935\u0938\u093e";break;case"dd":r="%d \u0926\u093f\u0935\u0938\u093e\u0902";break;case"M":r="\u090f\u0915\u093e \u092e\u0939\u093f\u0928\u094d\u092f\u093e";break;case"MM":r="%d \u092e\u0939\u093f\u0928\u094d\u092f\u093e\u0902";break;case"y":r="\u090f\u0915\u093e \u0935\u0930\u094d\u0937\u093e";break;case"yy":r="%d \u0935\u0930\u094d\u0937\u093e\u0902"}return r.replace(/%d/i,e)}e.defineLocale("mr",{months:"\u091c\u093e\u0928\u0947\u0935\u093e\u0930\u0940_\u092b\u0947\u092c\u094d\u0930\u0941\u0935\u093e\u0930\u0940_\u092e\u093e\u0930\u094d\u091a_\u090f\u092a\u094d\u0930\u093f\u0932_\u092e\u0947_\u091c\u0942\u0928_\u091c\u0941\u0932\u0948_\u0911\u0917\u0938\u094d\u091f_\u0938\u092a\u094d\u091f\u0947\u0902\u092c\u0930_\u0911\u0915\u094d\u091f\u094b\u092c\u0930_\u0928\u094b\u0935\u094d\u0939\u0947\u0902\u092c\u0930_\u0921\u093f\u0938\u0947\u0902\u092c\u0930".split("_"),monthsShort:"\u091c\u093e\u0928\u0947._\u092b\u0947\u092c\u094d\u0930\u0941._\u092e\u093e\u0930\u094d\u091a._\u090f\u092a\u094d\u0930\u093f._\u092e\u0947._\u091c\u0942\u0928._\u091c\u0941\u0932\u0948._\u0911\u0917._\u0938\u092a\u094d\u091f\u0947\u0902._\u0911\u0915\u094d\u091f\u094b._\u0928\u094b\u0935\u094d\u0939\u0947\u0902._\u0921\u093f\u0938\u0947\u0902.".split("_"),monthsParseExact:!0,weekdays:"\u0930\u0935\u093f\u0935\u093e\u0930_\u0938\u094b\u092e\u0935\u093e\u0930_\u092e\u0902\u0917\u0933\u0935\u093e\u0930_\u092c\u0941\u0927\u0935\u093e\u0930_\u0917\u0941\u0930\u0942\u0935\u093e\u0930_\u0936\u0941\u0915\u094d\u0930\u0935\u093e\u0930_\u0936\u0928\u093f\u0935\u093e\u0930".split("_"),weekdaysShort:"\u0930\u0935\u093f_\u0938\u094b\u092e_\u092e\u0902\u0917\u0933_\u092c\u0941\u0927_\u0917\u0941\u0930\u0942_\u0936\u0941\u0915\u094d\u0930_\u0936\u0928\u093f".split("_"),weekdaysMin:"\u0930_\u0938\u094b_\u092e\u0902_\u092c\u0941_\u0917\u0941_\u0936\u0941_\u0936".split("_"),longDateFormat:{LT:"A h:mm \u0935\u093e\u091c\u0924\u093e",LTS:"A h:mm:ss \u0935\u093e\u091c\u0924\u093e",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm \u0935\u093e\u091c\u0924\u093e",LLLL:"dddd, D MMMM YYYY, A h:mm \u0935\u093e\u091c\u0924\u093e"},calendar:{sameDay:"[\u0906\u091c] LT",nextDay:"[\u0909\u0926\u094d\u092f\u093e] LT",nextWeek:"dddd, LT",lastDay:"[\u0915\u093e\u0932] LT",lastWeek:"[\u092e\u093e\u0917\u0940\u0932] dddd, LT",sameElse:"L"},relativeTime:{future:"%s\u092e\u0927\u094d\u092f\u0947",past:"%s\u092a\u0942\u0930\u094d\u0935\u0940",s:i,ss:i,m:i,mm:i,h:i,hh:i,d:i,dd:i,M:i,MM:i,y:i,yy:i},preparse:function(e){return e.replace(/[\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u0966]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u092a\u0939\u093e\u091f\u0947|\u0938\u0915\u093e\u0933\u0940|\u0926\u0941\u092a\u093e\u0930\u0940|\u0938\u093e\u092f\u0902\u0915\u093e\u0933\u0940|\u0930\u093e\u0924\u094d\u0930\u0940/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u092a\u0939\u093e\u091f\u0947"===t||"\u0938\u0915\u093e\u0933\u0940"===t?e:"\u0926\u0941\u092a\u093e\u0930\u0940"===t||"\u0938\u093e\u092f\u0902\u0915\u093e\u0933\u0940"===t||"\u0930\u093e\u0924\u094d\u0930\u0940"===t?e>=12?e:e+12:void 0},meridiem:function(e,t,n){return e>=0&&e<6?"\u092a\u0939\u093e\u091f\u0947":e<12?"\u0938\u0915\u093e\u0933\u0940":e<17?"\u0926\u0941\u092a\u093e\u0930\u0940":e<20?"\u0938\u093e\u092f\u0902\u0915\u093e\u0933\u0940":"\u0930\u093e\u0924\u094d\u0930\u0940"},week:{dow:0,doy:6}})}(n("wd/R"))},OjkT:function(e,t,n){!function(e){"use strict";var t={1:"\u0967",2:"\u0968",3:"\u0969",4:"\u096a",5:"\u096b",6:"\u096c",7:"\u096d",8:"\u096e",9:"\u096f",0:"\u0966"},n={"\u0967":"1","\u0968":"2","\u0969":"3","\u096a":"4","\u096b":"5","\u096c":"6","\u096d":"7","\u096e":"8","\u096f":"9","\u0966":"0"};e.defineLocale("ne",{months:"\u091c\u0928\u0935\u0930\u0940_\u092b\u0947\u092c\u094d\u0930\u0941\u0935\u0930\u0940_\u092e\u093e\u0930\u094d\u091a_\u0905\u092a\u094d\u0930\u093f\u0932_\u092e\u0908_\u091c\u0941\u0928_\u091c\u0941\u0932\u093e\u0908_\u0905\u0917\u0937\u094d\u091f_\u0938\u0947\u092a\u094d\u091f\u0947\u092e\u094d\u092c\u0930_\u0905\u0915\u094d\u091f\u094b\u092c\u0930_\u0928\u094b\u092d\u0947\u092e\u094d\u092c\u0930_\u0921\u093f\u0938\u0947\u092e\u094d\u092c\u0930".split("_"),monthsShort:"\u091c\u0928._\u092b\u0947\u092c\u094d\u0930\u0941._\u092e\u093e\u0930\u094d\u091a_\u0905\u092a\u094d\u0930\u093f._\u092e\u0908_\u091c\u0941\u0928_\u091c\u0941\u0932\u093e\u0908._\u0905\u0917._\u0938\u0947\u092a\u094d\u091f._\u0905\u0915\u094d\u091f\u094b._\u0928\u094b\u092d\u0947._\u0921\u093f\u0938\u0947.".split("_"),monthsParseExact:!0,weekdays:"\u0906\u0907\u0924\u092c\u093e\u0930_\u0938\u094b\u092e\u092c\u093e\u0930_\u092e\u0919\u094d\u0917\u0932\u092c\u093e\u0930_\u092c\u0941\u0927\u092c\u093e\u0930_\u092c\u093f\u0939\u093f\u092c\u093e\u0930_\u0936\u0941\u0915\u094d\u0930\u092c\u093e\u0930_\u0936\u0928\u093f\u092c\u093e\u0930".split("_"),weekdaysShort:"\u0906\u0907\u0924._\u0938\u094b\u092e._\u092e\u0919\u094d\u0917\u0932._\u092c\u0941\u0927._\u092c\u093f\u0939\u093f._\u0936\u0941\u0915\u094d\u0930._\u0936\u0928\u093f.".split("_"),weekdaysMin:"\u0906._\u0938\u094b._\u092e\u0902._\u092c\u0941._\u092c\u093f._\u0936\u0941._\u0936.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A\u0915\u094b h:mm \u092c\u091c\u0947",LTS:"A\u0915\u094b h:mm:ss \u092c\u091c\u0947",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A\u0915\u094b h:mm \u092c\u091c\u0947",LLLL:"dddd, D MMMM YYYY, A\u0915\u094b h:mm \u092c\u091c\u0947"},preparse:function(e){return e.replace(/[\u0967\u0968\u0969\u096a\u096b\u096c\u096d\u096e\u096f\u0966]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0930\u093e\u0924\u093f|\u092c\u093f\u0939\u093e\u0928|\u0926\u093f\u0909\u0901\u0938\u094b|\u0938\u093e\u0901\u091d/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0930\u093e\u0924\u093f"===t?e<4?e:e+12:"\u092c\u093f\u0939\u093e\u0928"===t?e:"\u0926\u093f\u0909\u0901\u0938\u094b"===t?e>=10?e:e+12:"\u0938\u093e\u0901\u091d"===t?e+12:void 0},meridiem:function(e,t,n){return e<3?"\u0930\u093e\u0924\u093f":e<12?"\u092c\u093f\u0939\u093e\u0928":e<16?"\u0926\u093f\u0909\u0901\u0938\u094b":e<20?"\u0938\u093e\u0901\u091d":"\u0930\u093e\u0924\u093f"},calendar:{sameDay:"[\u0906\u091c] LT",nextDay:"[\u092d\u094b\u0932\u093f] LT",nextWeek:"[\u0906\u0909\u0901\u0926\u094b] dddd[,] LT",lastDay:"[\u0939\u093f\u091c\u094b] LT",lastWeek:"[\u0917\u090f\u0915\u094b] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s\u092e\u093e",past:"%s \u0905\u0917\u093e\u0921\u093f",s:"\u0915\u0947\u0939\u0940 \u0915\u094d\u0937\u0923",ss:"%d \u0938\u0947\u0915\u0947\u0923\u094d\u0921",m:"\u090f\u0915 \u092e\u093f\u0928\u0947\u091f",mm:"%d \u092e\u093f\u0928\u0947\u091f",h:"\u090f\u0915 \u0918\u0923\u094d\u091f\u093e",hh:"%d \u0918\u0923\u094d\u091f\u093e",d:"\u090f\u0915 \u0926\u093f\u0928",dd:"%d \u0926\u093f\u0928",M:"\u090f\u0915 \u092e\u0939\u093f\u0928\u093e",MM:"%d \u092e\u0939\u093f\u0928\u093e",y:"\u090f\u0915 \u092c\u0930\u094d\u0937",yy:"%d \u092c\u0930\u094d\u0937"},week:{dow:0,doy:6}})}(n("wd/R"))},OmwH:function(e,t,n){!function(e){"use strict";e.defineLocale("zh-mo",{months:"\u4e00\u6708_\u4e8c\u6708_\u4e09\u6708_\u56db\u6708_\u4e94\u6708_\u516d\u6708_\u4e03\u6708_\u516b\u6708_\u4e5d\u6708_\u5341\u6708_\u5341\u4e00\u6708_\u5341\u4e8c\u6708".split("_"),monthsShort:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),weekdays:"\u661f\u671f\u65e5_\u661f\u671f\u4e00_\u661f\u671f\u4e8c_\u661f\u671f\u4e09_\u661f\u671f\u56db_\u661f\u671f\u4e94_\u661f\u671f\u516d".split("_"),weekdaysShort:"\u9031\u65e5_\u9031\u4e00_\u9031\u4e8c_\u9031\u4e09_\u9031\u56db_\u9031\u4e94_\u9031\u516d".split("_"),weekdaysMin:"\u65e5_\u4e00_\u4e8c_\u4e09_\u56db_\u4e94_\u516d".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"YYYY\u5e74M\u6708D\u65e5",LLL:"YYYY\u5e74M\u6708D\u65e5 HH:mm",LLLL:"YYYY\u5e74M\u6708D\u65e5dddd HH:mm",l:"D/M/YYYY",ll:"YYYY\u5e74M\u6708D\u65e5",lll:"YYYY\u5e74M\u6708D\u65e5 HH:mm",llll:"YYYY\u5e74M\u6708D\u65e5dddd HH:mm"},meridiemParse:/\u51cc\u6668|\u65e9\u4e0a|\u4e0a\u5348|\u4e2d\u5348|\u4e0b\u5348|\u665a\u4e0a/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u51cc\u6668"===t||"\u65e9\u4e0a"===t||"\u4e0a\u5348"===t?e:"\u4e2d\u5348"===t?e>=11?e:e+12:"\u4e0b\u5348"===t||"\u665a\u4e0a"===t?e+12:void 0},meridiem:function(e,t,n){var i=100*e+t;return i<600?"\u51cc\u6668":i<900?"\u65e9\u4e0a":i<1130?"\u4e0a\u5348":i<1230?"\u4e2d\u5348":i<1800?"\u4e0b\u5348":"\u665a\u4e0a"},calendar:{sameDay:"[\u4eca\u5929] LT",nextDay:"[\u660e\u5929] LT",nextWeek:"[\u4e0b]dddd LT",lastDay:"[\u6628\u5929] LT",lastWeek:"[\u4e0a]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(\u65e5|\u6708|\u9031)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"\u65e5";case"M":return e+"\u6708";case"w":case"W":return e+"\u9031";default:return e}},relativeTime:{future:"%s\u5167",past:"%s\u524d",s:"\u5e7e\u79d2",ss:"%d \u79d2",m:"1 \u5206\u9418",mm:"%d \u5206\u9418",h:"1 \u5c0f\u6642",hh:"%d \u5c0f\u6642",d:"1 \u5929",dd:"%d \u5929",M:"1 \u500b\u6708",MM:"%d \u500b\u6708",y:"1 \u5e74",yy:"%d \u5e74"}})}(n("wd/R"))},Oxv6:function(e,t,n){!function(e){"use strict";var t={0:"-\u0443\u043c",1:"-\u0443\u043c",2:"-\u044e\u043c",3:"-\u044e\u043c",4:"-\u0443\u043c",5:"-\u0443\u043c",6:"-\u0443\u043c",7:"-\u0443\u043c",8:"-\u0443\u043c",9:"-\u0443\u043c",10:"-\u0443\u043c",12:"-\u0443\u043c",13:"-\u0443\u043c",20:"-\u0443\u043c",30:"-\u044e\u043c",40:"-\u0443\u043c",50:"-\u0443\u043c",60:"-\u0443\u043c",70:"-\u0443\u043c",80:"-\u0443\u043c",90:"-\u0443\u043c",100:"-\u0443\u043c"};e.defineLocale("tg",{months:{format:"\u044f\u043d\u0432\u0430\u0440\u0438_\u0444\u0435\u0432\u0440\u0430\u043b\u0438_\u043c\u0430\u0440\u0442\u0438_\u0430\u043f\u0440\u0435\u043b\u0438_\u043c\u0430\u0439\u0438_\u0438\u044e\u043d\u0438_\u0438\u044e\u043b\u0438_\u0430\u0432\u0433\u0443\u0441\u0442\u0438_\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u0438_\u043e\u043a\u0442\u044f\u0431\u0440\u0438_\u043d\u043e\u044f\u0431\u0440\u0438_\u0434\u0435\u043a\u0430\u0431\u0440\u0438".split("_"),standalone:"\u044f\u043d\u0432\u0430\u0440_\u0444\u0435\u0432\u0440\u0430\u043b_\u043c\u0430\u0440\u0442_\u0430\u043f\u0440\u0435\u043b_\u043c\u0430\u0439_\u0438\u044e\u043d_\u0438\u044e\u043b_\u0430\u0432\u0433\u0443\u0441\u0442_\u0441\u0435\u043d\u0442\u044f\u0431\u0440_\u043e\u043a\u0442\u044f\u0431\u0440_\u043d\u043e\u044f\u0431\u0440_\u0434\u0435\u043a\u0430\u0431\u0440".split("_")},monthsShort:"\u044f\u043d\u0432_\u0444\u0435\u0432_\u043c\u0430\u0440_\u0430\u043f\u0440_\u043c\u0430\u0439_\u0438\u044e\u043d_\u0438\u044e\u043b_\u0430\u0432\u0433_\u0441\u0435\u043d_\u043e\u043a\u0442_\u043d\u043e\u044f_\u0434\u0435\u043a".split("_"),weekdays:"\u044f\u043a\u0448\u0430\u043d\u0431\u0435_\u0434\u0443\u0448\u0430\u043d\u0431\u0435_\u0441\u0435\u0448\u0430\u043d\u0431\u0435_\u0447\u043e\u0440\u0448\u0430\u043d\u0431\u0435_\u043f\u0430\u043d\u04b7\u0448\u0430\u043d\u0431\u0435_\u04b7\u0443\u043c\u044a\u0430_\u0448\u0430\u043d\u0431\u0435".split("_"),weekdaysShort:"\u044f\u0448\u0431_\u0434\u0448\u0431_\u0441\u0448\u0431_\u0447\u0448\u0431_\u043f\u0448\u0431_\u04b7\u0443\u043c_\u0448\u043d\u0431".split("_"),weekdaysMin:"\u044f\u0448_\u0434\u0448_\u0441\u0448_\u0447\u0448_\u043f\u0448_\u04b7\u043c_\u0448\u0431".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[\u0418\u043c\u0440\u04ef\u0437 \u0441\u043e\u0430\u0442\u0438] LT",nextDay:"[\u0424\u0430\u0440\u0434\u043e \u0441\u043e\u0430\u0442\u0438] LT",lastDay:"[\u0414\u0438\u0440\u04ef\u0437 \u0441\u043e\u0430\u0442\u0438] LT",nextWeek:"dddd[\u0438] [\u04b3\u0430\u0444\u0442\u0430\u0438 \u043e\u044f\u043d\u0434\u0430 \u0441\u043e\u0430\u0442\u0438] LT",lastWeek:"dddd[\u0438] [\u04b3\u0430\u0444\u0442\u0430\u0438 \u0433\u0443\u0437\u0430\u0448\u0442\u0430 \u0441\u043e\u0430\u0442\u0438] LT",sameElse:"L"},relativeTime:{future:"\u0431\u0430\u044a\u0434\u0438 %s",past:"%s \u043f\u0435\u0448",s:"\u044f\u043a\u0447\u0430\u043d\u0434 \u0441\u043e\u043d\u0438\u044f",m:"\u044f\u043a \u0434\u0430\u049b\u0438\u049b\u0430",mm:"%d \u0434\u0430\u049b\u0438\u049b\u0430",h:"\u044f\u043a \u0441\u043e\u0430\u0442",hh:"%d \u0441\u043e\u0430\u0442",d:"\u044f\u043a \u0440\u04ef\u0437",dd:"%d \u0440\u04ef\u0437",M:"\u044f\u043a \u043c\u043e\u04b3",MM:"%d \u043c\u043e\u04b3",y:"\u044f\u043a \u0441\u043e\u043b",yy:"%d \u0441\u043e\u043b"},meridiemParse:/\u0448\u0430\u0431|\u0441\u0443\u0431\u04b3|\u0440\u04ef\u0437|\u0431\u0435\u0433\u043e\u04b3/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0448\u0430\u0431"===t?e<4?e:e+12:"\u0441\u0443\u0431\u04b3"===t?e:"\u0440\u04ef\u0437"===t?e>=11?e:e+12:"\u0431\u0435\u0433\u043e\u04b3"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"\u0448\u0430\u0431":e<11?"\u0441\u0443\u0431\u04b3":e<16?"\u0440\u04ef\u0437":e<19?"\u0431\u0435\u0433\u043e\u04b3":"\u0448\u0430\u0431"},dayOfMonthOrdinalParse:/\d{1,2}-(\u0443\u043c|\u044e\u043c)/,ordinal:function(e){return e+(t[e]||t[e%10]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(n("wd/R"))},P4y1:function(e,t){e.exports={}},P8lu:function(e,t,n){"use strict";n.d(t,"a",(function(){return m}));var i=n("mrSG"),r=n("IheW"),s=n("LvDl"),o=n.n(s),a=n("cp0P"),c=n("LRne"),l=n("5+tZ"),u=n("CqXF"),d=n("JIr8"),h=n("9xzX"),f=n("xTzq"),p=n("8Y7J");let m=(()=>{let e=class{constructor(e,t){this.http=e,this.rgwDaemonService=t,this.url="api/rgw/user"}list(){return this.enumerate().pipe(Object(l.a)(e=>e.length>0?Object(a.a)(e.map(e=>this.get(e))):Object(c.a)([])))}enumerate(){return this.rgwDaemonService.request(e=>this.http.get(this.url,{params:e}))}enumerateEmail(){return this.rgwDaemonService.request(e=>this.http.get(this.url+"/get_emails",{params:e}))}get(e){return this.rgwDaemonService.request(t=>this.http.get(`${this.url}/${e}`,{params:t}))}getQuota(e){return this.rgwDaemonService.request(t=>this.http.get(`${this.url}/${e}/quota`,{params:t}))}create(e){return this.rgwDaemonService.request(t=>(o.a.keys(e).forEach(n=>{t=t.append(n,e[n])}),this.http.post(this.url,null,{params:t})))}update(e,t){return this.rgwDaemonService.request(n=>(o.a.keys(t).forEach(e=>{n=n.append(e,t[e])}),this.http.put(`${this.url}/${e}`,null,{params:n})))}updateQuota(e,t){return this.rgwDaemonService.request(n=>(o.a.keys(t).forEach(e=>{n=n.append(e,t[e])}),this.http.put(`${this.url}/${e}/quota`,null,{params:n})))}delete(e){return this.rgwDaemonService.request(t=>this.http.delete(`${this.url}/${e}`,{params:t}))}createSubuser(e,t){return this.rgwDaemonService.request(n=>(o.a.keys(t).forEach(e=>{n=n.append(e,t[e])}),this.http.post(`${this.url}/${e}/subuser`,null,{params:n})))}deleteSubuser(e,t){return this.rgwDaemonService.request(n=>this.http.delete(`${this.url}/${e}/subuser/${t}`,{params:n}))}addCapability(e,t,n){return this.rgwDaemonService.request(i=>(i=(i=i.append("type",t)).append("perm",n),this.http.post(`${this.url}/${e}/capability`,null,{params:i})))}deleteCapability(e,t,n){return this.rgwDaemonService.request(i=>(i=(i=i.append("type",t)).append("perm",n),this.http.delete(`${this.url}/${e}/capability`,{params:i})))}addS3Key(e,t){return this.rgwDaemonService.request(n=>(n=n.append("key_type","s3"),o.a.keys(t).forEach(e=>{n=n.append(e,t[e])}),this.http.post(`${this.url}/${e}/key`,null,{params:n})))}deleteS3Key(e,t){return this.rgwDaemonService.request(n=>(n=(n=n.append("key_type","s3")).append("access_key",t),this.http.delete(`${this.url}/${e}/key`,{params:n})))}exists(e){return this.get(e).pipe(Object(u.a)(!0),Object(d.a)(e=>(o.a.isFunction(e.preventDefault)&&e.preventDefault(),Object(c.a)(!1))))}emailExists(e){return e=decodeURIComponent(e),this.enumerateEmail().pipe(Object(l.a)(t=>{const n=o.a.indexOf(t,e);return Object(c.a)(-1!==n)}))}};return e.\u0275fac=function(t){return new(t||e)(p.dc(r.b),p.dc(h.a))},e.\u0275prov=p.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e=Object(i.b)([f.a,Object(i.d)("design:paramtypes",[r.b,h.a])],e),e})()},PA2r:function(e,t,n){!function(e){"use strict";var t="leden_\xfanor_b\u0159ezen_duben_kv\u011bten_\u010derven_\u010dervenec_srpen_z\xe1\u0159\xed_\u0159\xedjen_listopad_prosinec".split("_"),n="led_\xfano_b\u0159e_dub_kv\u011b_\u010dvn_\u010dvc_srp_z\xe1\u0159_\u0159\xedj_lis_pro".split("_"),i=[/^led/i,/^\xfano/i,/^b\u0159e/i,/^dub/i,/^kv\u011b/i,/^(\u010dvn|\u010derven$|\u010dervna)/i,/^(\u010dvc|\u010dervenec|\u010dervence)/i,/^srp/i,/^z\xe1\u0159/i,/^\u0159\xedj/i,/^lis/i,/^pro/i],r=/^(leden|\xfanor|b\u0159ezen|duben|kv\u011bten|\u010dervenec|\u010dervence|\u010derven|\u010dervna|srpen|z\xe1\u0159\xed|\u0159\xedjen|listopad|prosinec|led|\xfano|b\u0159e|dub|kv\u011b|\u010dvn|\u010dvc|srp|z\xe1\u0159|\u0159\xedj|lis|pro)/i;function s(e){return e>1&&e<5&&1!=~~(e/10)}function o(e,t,n,i){var r=e+" ";switch(n){case"s":return t||i?"p\xe1r sekund":"p\xe1r sekundami";case"ss":return t||i?r+(s(e)?"sekundy":"sekund"):r+"sekundami";case"m":return t?"minuta":i?"minutu":"minutou";case"mm":return t||i?r+(s(e)?"minuty":"minut"):r+"minutami";case"h":return t?"hodina":i?"hodinu":"hodinou";case"hh":return t||i?r+(s(e)?"hodiny":"hodin"):r+"hodinami";case"d":return t||i?"den":"dnem";case"dd":return t||i?r+(s(e)?"dny":"dn\xed"):r+"dny";case"M":return t||i?"m\u011bs\xedc":"m\u011bs\xedcem";case"MM":return t||i?r+(s(e)?"m\u011bs\xedce":"m\u011bs\xedc\u016f"):r+"m\u011bs\xedci";case"y":return t||i?"rok":"rokem";case"yy":return t||i?r+(s(e)?"roky":"let"):r+"lety"}}e.defineLocale("cs",{months:t,monthsShort:n,monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:/^(leden|ledna|\xfanora|\xfanor|b\u0159ezen|b\u0159ezna|duben|dubna|kv\u011bten|kv\u011btna|\u010dervenec|\u010dervence|\u010derven|\u010dervna|srpen|srpna|z\xe1\u0159\xed|\u0159\xedjen|\u0159\xedjna|listopadu|listopad|prosinec|prosince)/i,monthsShortStrictRegex:/^(led|\xfano|b\u0159e|dub|kv\u011b|\u010dvn|\u010dvc|srp|z\xe1\u0159|\u0159\xedj|lis|pro)/i,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,weekdays:"ned\u011ble_pond\u011bl\xed_\xfater\xfd_st\u0159eda_\u010dtvrtek_p\xe1tek_sobota".split("_"),weekdaysShort:"ne_po_\xfat_st_\u010dt_p\xe1_so".split("_"),weekdaysMin:"ne_po_\xfat_st_\u010dt_p\xe1_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[z\xedtra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v ned\u011bli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve st\u0159edu v] LT";case 4:return"[ve \u010dtvrtek v] LT";case 5:return"[v p\xe1tek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[v\u010dera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou ned\u011bli v] LT";case 1:case 2:return"[minul\xe9] dddd [v] LT";case 3:return"[minulou st\u0159edu v] LT";case 4:case 5:return"[minul\xfd] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"p\u0159ed %s",s:o,ss:o,m:o,mm:o,h:o,hh:o,d:o,dd:o,M:o,MM:o,y:o,yy:o},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},PCNd:function(e,t,n){"use strict";n.d(t,"a",(function(){return f}));var i=n("SVse"),r=n("TKcr"),s=n("V/fk"),o=n("ChqD"),a=n("yGOH"),c=n("9Xeq"),l=n("Avrn"),u=n("aexS"),d=n("aXbf"),h=n("8Y7J");let f=(()=>{class e{}return e.\u0275mod=h.Kb({type:e}),e.\u0275inj=h.Jb({factory:function(t){return new(t||e)},providers:[u.a,l.a,d.a,r.a],imports:[[i.c,c.a,s.a,o.a,a.a],s.a,c.a,o.a,a.a]}),e})()},PKPk:function(e,t,n){"use strict";var i=n("ZUd8").charAt,r=n("afO8"),s=n("fdAy"),o="String Iterator",a=r.set,c=r.getterFor(o);s(String,"String",(function(e){a(this,{type:o,string:String(e),index:0})}),(function(){var e,t=c(this),n=t.string,r=t.index;return r>=n.length?{value:void 0,done:!0}:(e=i(n,r),t.index+=e.length,{value:e,done:!1})}))},PeUW:function(e,t,n){!function(e){"use strict";var t={1:"\u0be7",2:"\u0be8",3:"\u0be9",4:"\u0bea",5:"\u0beb",6:"\u0bec",7:"\u0bed",8:"\u0bee",9:"\u0bef",0:"\u0be6"},n={"\u0be7":"1","\u0be8":"2","\u0be9":"3","\u0bea":"4","\u0beb":"5","\u0bec":"6","\u0bed":"7","\u0bee":"8","\u0bef":"9","\u0be6":"0"};e.defineLocale("ta",{months:"\u0b9c\u0ba9\u0bb5\u0bb0\u0bbf_\u0baa\u0bbf\u0baa\u0bcd\u0bb0\u0bb5\u0bb0\u0bbf_\u0bae\u0bbe\u0bb0\u0bcd\u0b9a\u0bcd_\u0b8f\u0baa\u0bcd\u0bb0\u0bb2\u0bcd_\u0bae\u0bc7_\u0b9c\u0bc2\u0ba9\u0bcd_\u0b9c\u0bc2\u0bb2\u0bc8_\u0b86\u0b95\u0bb8\u0bcd\u0b9f\u0bcd_\u0b9a\u0bc6\u0baa\u0bcd\u0b9f\u0bc6\u0bae\u0bcd\u0baa\u0bb0\u0bcd_\u0b85\u0b95\u0bcd\u0b9f\u0bc7\u0bbe\u0baa\u0bb0\u0bcd_\u0ba8\u0bb5\u0bae\u0bcd\u0baa\u0bb0\u0bcd_\u0b9f\u0bbf\u0b9a\u0bae\u0bcd\u0baa\u0bb0\u0bcd".split("_"),monthsShort:"\u0b9c\u0ba9\u0bb5\u0bb0\u0bbf_\u0baa\u0bbf\u0baa\u0bcd\u0bb0\u0bb5\u0bb0\u0bbf_\u0bae\u0bbe\u0bb0\u0bcd\u0b9a\u0bcd_\u0b8f\u0baa\u0bcd\u0bb0\u0bb2\u0bcd_\u0bae\u0bc7_\u0b9c\u0bc2\u0ba9\u0bcd_\u0b9c\u0bc2\u0bb2\u0bc8_\u0b86\u0b95\u0bb8\u0bcd\u0b9f\u0bcd_\u0b9a\u0bc6\u0baa\u0bcd\u0b9f\u0bc6\u0bae\u0bcd\u0baa\u0bb0\u0bcd_\u0b85\u0b95\u0bcd\u0b9f\u0bc7\u0bbe\u0baa\u0bb0\u0bcd_\u0ba8\u0bb5\u0bae\u0bcd\u0baa\u0bb0\u0bcd_\u0b9f\u0bbf\u0b9a\u0bae\u0bcd\u0baa\u0bb0\u0bcd".split("_"),weekdays:"\u0b9e\u0bbe\u0baf\u0bbf\u0bb1\u0bcd\u0bb1\u0bc1\u0b95\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8_\u0ba4\u0bbf\u0b99\u0bcd\u0b95\u0b9f\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8_\u0b9a\u0bc6\u0bb5\u0bcd\u0bb5\u0bbe\u0baf\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8_\u0baa\u0bc1\u0ba4\u0ba9\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8_\u0bb5\u0bbf\u0baf\u0bbe\u0bb4\u0b95\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8_\u0bb5\u0bc6\u0bb3\u0bcd\u0bb3\u0bbf\u0b95\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8_\u0b9a\u0ba9\u0bbf\u0b95\u0bcd\u0b95\u0bbf\u0bb4\u0bae\u0bc8".split("_"),weekdaysShort:"\u0b9e\u0bbe\u0baf\u0bbf\u0bb1\u0bc1_\u0ba4\u0bbf\u0b99\u0bcd\u0b95\u0bb3\u0bcd_\u0b9a\u0bc6\u0bb5\u0bcd\u0bb5\u0bbe\u0baf\u0bcd_\u0baa\u0bc1\u0ba4\u0ba9\u0bcd_\u0bb5\u0bbf\u0baf\u0bbe\u0bb4\u0ba9\u0bcd_\u0bb5\u0bc6\u0bb3\u0bcd\u0bb3\u0bbf_\u0b9a\u0ba9\u0bbf".split("_"),weekdaysMin:"\u0b9e\u0bbe_\u0ba4\u0bbf_\u0b9a\u0bc6_\u0baa\u0bc1_\u0bb5\u0bbf_\u0bb5\u0bc6_\u0b9a".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[\u0b87\u0ba9\u0bcd\u0bb1\u0bc1] LT",nextDay:"[\u0ba8\u0bbe\u0bb3\u0bc8] LT",nextWeek:"dddd, LT",lastDay:"[\u0ba8\u0bc7\u0bb1\u0bcd\u0bb1\u0bc1] LT",lastWeek:"[\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 \u0bb5\u0bbe\u0bb0\u0bae\u0bcd] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0b87\u0bb2\u0bcd",past:"%s \u0bae\u0bc1\u0ba9\u0bcd",s:"\u0b92\u0bb0\u0bc1 \u0b9a\u0bbf\u0bb2 \u0bb5\u0bbf\u0ba8\u0bbe\u0b9f\u0bbf\u0b95\u0bb3\u0bcd",ss:"%d \u0bb5\u0bbf\u0ba8\u0bbe\u0b9f\u0bbf\u0b95\u0bb3\u0bcd",m:"\u0b92\u0bb0\u0bc1 \u0ba8\u0bbf\u0bae\u0bbf\u0b9f\u0bae\u0bcd",mm:"%d \u0ba8\u0bbf\u0bae\u0bbf\u0b9f\u0b99\u0bcd\u0b95\u0bb3\u0bcd",h:"\u0b92\u0bb0\u0bc1 \u0bae\u0ba3\u0bbf \u0ba8\u0bc7\u0bb0\u0bae\u0bcd",hh:"%d \u0bae\u0ba3\u0bbf \u0ba8\u0bc7\u0bb0\u0bae\u0bcd",d:"\u0b92\u0bb0\u0bc1 \u0ba8\u0bbe\u0bb3\u0bcd",dd:"%d \u0ba8\u0bbe\u0b9f\u0bcd\u0b95\u0bb3\u0bcd",M:"\u0b92\u0bb0\u0bc1 \u0bae\u0bbe\u0ba4\u0bae\u0bcd",MM:"%d \u0bae\u0bbe\u0ba4\u0b99\u0bcd\u0b95\u0bb3\u0bcd",y:"\u0b92\u0bb0\u0bc1 \u0bb5\u0bb0\u0bc1\u0b9f\u0bae\u0bcd",yy:"%d \u0b86\u0ba3\u0bcd\u0b9f\u0bc1\u0b95\u0bb3\u0bcd"},dayOfMonthOrdinalParse:/\d{1,2}\u0bb5\u0ba4\u0bc1/,ordinal:function(e){return e+"\u0bb5\u0ba4\u0bc1"},preparse:function(e){return e.replace(/[\u0be7\u0be8\u0be9\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0be6]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0baf\u0bbe\u0bae\u0bae\u0bcd|\u0bb5\u0bc8\u0b95\u0bb1\u0bc8|\u0b95\u0bbe\u0bb2\u0bc8|\u0ba8\u0ba3\u0bcd\u0baa\u0b95\u0bb2\u0bcd|\u0b8e\u0bb1\u0bcd\u0baa\u0bbe\u0b9f\u0bc1|\u0bae\u0bbe\u0bb2\u0bc8/,meridiem:function(e,t,n){return e<2?" \u0baf\u0bbe\u0bae\u0bae\u0bcd":e<6?" \u0bb5\u0bc8\u0b95\u0bb1\u0bc8":e<10?" \u0b95\u0bbe\u0bb2\u0bc8":e<14?" \u0ba8\u0ba3\u0bcd\u0baa\u0b95\u0bb2\u0bcd":e<18?" \u0b8e\u0bb1\u0bcd\u0baa\u0bbe\u0b9f\u0bc1":e<22?" \u0bae\u0bbe\u0bb2\u0bc8":" \u0baf\u0bbe\u0bae\u0bae\u0bcd"},meridiemHour:function(e,t){return 12===e&&(e=0),"\u0baf\u0bbe\u0bae\u0bae\u0bcd"===t?e<2?e:e+12:"\u0bb5\u0bc8\u0b95\u0bb1\u0bc8"===t||"\u0b95\u0bbe\u0bb2\u0bc8"===t||"\u0ba8\u0ba3\u0bcd\u0baa\u0b95\u0bb2\u0bcd"===t&&e>=10?e:e+12},week:{dow:0,doy:6}})}(n("wd/R"))},PhyI:function(e,t,n){"use strict";n.d(t,"a",(function(){return i})),n.d(t,"b",(function(){return r}));var i=function(e){return e[e.global=0]="global",e[e.pool=1]="pool",e[e.image=2]="image",e}({}),r=function(e){return e[e.bps=0]="bps",e[e.iops=1]="iops",e[e.milliseconds=2]="milliseconds",e}({})},PpIw:function(e,t,n){!function(e){"use strict";var t={1:"\u0ce7",2:"\u0ce8",3:"\u0ce9",4:"\u0cea",5:"\u0ceb",6:"\u0cec",7:"\u0ced",8:"\u0cee",9:"\u0cef",0:"\u0ce6"},n={"\u0ce7":"1","\u0ce8":"2","\u0ce9":"3","\u0cea":"4","\u0ceb":"5","\u0cec":"6","\u0ced":"7","\u0cee":"8","\u0cef":"9","\u0ce6":"0"};e.defineLocale("kn",{months:"\u0c9c\u0ca8\u0cb5\u0cb0\u0cbf_\u0cab\u0cc6\u0cac\u0ccd\u0cb0\u0cb5\u0cb0\u0cbf_\u0cae\u0cbe\u0cb0\u0ccd\u0c9a\u0ccd_\u0c8f\u0caa\u0ccd\u0cb0\u0cbf\u0cb2\u0ccd_\u0cae\u0cc6\u0cd5_\u0c9c\u0cc2\u0ca8\u0ccd_\u0c9c\u0cc1\u0cb2\u0cc6\u0cd6_\u0c86\u0c97\u0cb8\u0ccd\u0c9f\u0ccd_\u0cb8\u0cc6\u0caa\u0ccd\u0c9f\u0cc6\u0c82\u0cac\u0cb0\u0ccd_\u0c85\u0c95\u0ccd\u0c9f\u0cc6\u0cc2\u0cd5\u0cac\u0cb0\u0ccd_\u0ca8\u0cb5\u0cc6\u0c82\u0cac\u0cb0\u0ccd_\u0ca1\u0cbf\u0cb8\u0cc6\u0c82\u0cac\u0cb0\u0ccd".split("_"),monthsShort:"\u0c9c\u0ca8_\u0cab\u0cc6\u0cac\u0ccd\u0cb0_\u0cae\u0cbe\u0cb0\u0ccd\u0c9a\u0ccd_\u0c8f\u0caa\u0ccd\u0cb0\u0cbf\u0cb2\u0ccd_\u0cae\u0cc6\u0cd5_\u0c9c\u0cc2\u0ca8\u0ccd_\u0c9c\u0cc1\u0cb2\u0cc6\u0cd6_\u0c86\u0c97\u0cb8\u0ccd\u0c9f\u0ccd_\u0cb8\u0cc6\u0caa\u0ccd\u0c9f\u0cc6\u0c82_\u0c85\u0c95\u0ccd\u0c9f\u0cc6\u0cc2\u0cd5_\u0ca8\u0cb5\u0cc6\u0c82_\u0ca1\u0cbf\u0cb8\u0cc6\u0c82".split("_"),monthsParseExact:!0,weekdays:"\u0cad\u0cbe\u0ca8\u0cc1\u0cb5\u0cbe\u0cb0_\u0cb8\u0cc6\u0cc2\u0cd5\u0cae\u0cb5\u0cbe\u0cb0_\u0cae\u0c82\u0c97\u0cb3\u0cb5\u0cbe\u0cb0_\u0cac\u0cc1\u0ca7\u0cb5\u0cbe\u0cb0_\u0c97\u0cc1\u0cb0\u0cc1\u0cb5\u0cbe\u0cb0_\u0cb6\u0cc1\u0c95\u0ccd\u0cb0\u0cb5\u0cbe\u0cb0_\u0cb6\u0ca8\u0cbf\u0cb5\u0cbe\u0cb0".split("_"),weekdaysShort:"\u0cad\u0cbe\u0ca8\u0cc1_\u0cb8\u0cc6\u0cc2\u0cd5\u0cae_\u0cae\u0c82\u0c97\u0cb3_\u0cac\u0cc1\u0ca7_\u0c97\u0cc1\u0cb0\u0cc1_\u0cb6\u0cc1\u0c95\u0ccd\u0cb0_\u0cb6\u0ca8\u0cbf".split("_"),weekdaysMin:"\u0cad\u0cbe_\u0cb8\u0cc6\u0cc2\u0cd5_\u0cae\u0c82_\u0cac\u0cc1_\u0c97\u0cc1_\u0cb6\u0cc1_\u0cb6".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[\u0c87\u0c82\u0ca6\u0cc1] LT",nextDay:"[\u0ca8\u0cbe\u0cb3\u0cc6] LT",nextWeek:"dddd, LT",lastDay:"[\u0ca8\u0cbf\u0ca8\u0ccd\u0ca8\u0cc6] LT",lastWeek:"[\u0c95\u0cc6\u0cc2\u0ca8\u0cc6\u0caf] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0ca8\u0c82\u0ca4\u0cb0",past:"%s \u0cb9\u0cbf\u0c82\u0ca6\u0cc6",s:"\u0c95\u0cc6\u0cb2\u0cb5\u0cc1 \u0c95\u0ccd\u0cb7\u0ca3\u0c97\u0cb3\u0cc1",ss:"%d \u0cb8\u0cc6\u0c95\u0cc6\u0c82\u0ca1\u0cc1\u0c97\u0cb3\u0cc1",m:"\u0c92\u0c82\u0ca6\u0cc1 \u0ca8\u0cbf\u0cae\u0cbf\u0cb7",mm:"%d \u0ca8\u0cbf\u0cae\u0cbf\u0cb7",h:"\u0c92\u0c82\u0ca6\u0cc1 \u0c97\u0c82\u0c9f\u0cc6",hh:"%d \u0c97\u0c82\u0c9f\u0cc6",d:"\u0c92\u0c82\u0ca6\u0cc1 \u0ca6\u0cbf\u0ca8",dd:"%d \u0ca6\u0cbf\u0ca8",M:"\u0c92\u0c82\u0ca6\u0cc1 \u0ca4\u0cbf\u0c82\u0c97\u0cb3\u0cc1",MM:"%d \u0ca4\u0cbf\u0c82\u0c97\u0cb3\u0cc1",y:"\u0c92\u0c82\u0ca6\u0cc1 \u0cb5\u0cb0\u0ccd\u0cb7",yy:"%d \u0cb5\u0cb0\u0ccd\u0cb7"},preparse:function(e){return e.replace(/[\u0ce7\u0ce8\u0ce9\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0ce6]/g,(function(e){return n[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/\u0cb0\u0cbe\u0ca4\u0ccd\u0cb0\u0cbf|\u0cac\u0cc6\u0cb3\u0cbf\u0c97\u0ccd\u0c97\u0cc6|\u0cae\u0ca7\u0ccd\u0caf\u0cbe\u0cb9\u0ccd\u0ca8|\u0cb8\u0c82\u0c9c\u0cc6/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0cb0\u0cbe\u0ca4\u0ccd\u0cb0\u0cbf"===t?e<4?e:e+12:"\u0cac\u0cc6\u0cb3\u0cbf\u0c97\u0ccd\u0c97\u0cc6"===t?e:"\u0cae\u0ca7\u0ccd\u0caf\u0cbe\u0cb9\u0ccd\u0ca8"===t?e>=10?e:e+12:"\u0cb8\u0c82\u0c9c\u0cc6"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"\u0cb0\u0cbe\u0ca4\u0ccd\u0cb0\u0cbf":e<10?"\u0cac\u0cc6\u0cb3\u0cbf\u0c97\u0ccd\u0c97\u0cc6":e<17?"\u0cae\u0ca7\u0ccd\u0caf\u0cbe\u0cb9\u0ccd\u0ca8":e<20?"\u0cb8\u0c82\u0c9c\u0cc6":"\u0cb0\u0cbe\u0ca4\u0ccd\u0cb0\u0cbf"},dayOfMonthOrdinalParse:/\d{1,2}(\u0ca8\u0cc6\u0cd5)/,ordinal:function(e){return e+"\u0ca8\u0cc6\u0cd5"},week:{dow:0,doy:6}})}(n("wd/R"))},PqYM:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("HDdC"),r=n("D0XW"),s=n("Y7HM"),o=n("z+Ro");function a(e=0,t,n){let a=-1;return Object(s.a)(t)?a=Number(t)<1?1:Number(t):Object(o.a)(t)&&(n=t),Object(o.a)(n)||(n=r.a),new i.a(t=>{const i=Object(s.a)(e)?e:+e-n.now();return n.schedule(c,i,{index:0,period:a,subscriber:t})})}function c(e){const{index:t,period:n,subscriber:i}=e;if(i.next(t),!i.closed){if(-1===n)return i.complete();e.index=t+1,this.schedule(e,n)}}},QFaf:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("s7LF");class r extends i.j{constructor(e,t,n){super(e,t,n),this.controls=e}get(e){const t=this._get(e);if(!t)throw new Error(`Control '${e}' could not be found!`);return t}_get(e){return super.get(e)||Object.values(this.controls).filter(e=>e.get).map(t=>t instanceof r?t._get(e):t.get(e)).find(e=>Boolean(e))}getValue(e){return this.get(e).value}silentSet(e,t){this.get(e).setValue(t,{emitEvent:!1})}showError(e,t,n){const i=this.get(e);return(t.submitted||i.dirty)&&(n?i.hasError(n):i.invalid)}}},QTAa:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("t/zF");class r extends i.a{}},QWBl:function(e,t,n){"use strict";var i=n("I+eb"),r=n("F8JR");i({target:"Array",proto:!0,forced:[].forEach!=r},{forEach:r})},Qj4J:function(e,t,n){!function(e){"use strict";e.defineLocale("ar-kw",{months:"\u064a\u0646\u0627\u064a\u0631_\u0641\u0628\u0631\u0627\u064a\u0631_\u0645\u0627\u0631\u0633_\u0623\u0628\u0631\u064a\u0644_\u0645\u0627\u064a_\u064a\u0648\u0646\u064a\u0648_\u064a\u0648\u0644\u064a\u0648\u0632_\u063a\u0634\u062a_\u0634\u062a\u0646\u0628\u0631_\u0623\u0643\u062a\u0648\u0628\u0631_\u0646\u0648\u0646\u0628\u0631_\u062f\u062c\u0646\u0628\u0631".split("_"),monthsShort:"\u064a\u0646\u0627\u064a\u0631_\u0641\u0628\u0631\u0627\u064a\u0631_\u0645\u0627\u0631\u0633_\u0623\u0628\u0631\u064a\u0644_\u0645\u0627\u064a_\u064a\u0648\u0646\u064a\u0648_\u064a\u0648\u0644\u064a\u0648\u0632_\u063a\u0634\u062a_\u0634\u062a\u0646\u0628\u0631_\u0623\u0643\u062a\u0648\u0628\u0631_\u0646\u0648\u0646\u0628\u0631_\u062f\u062c\u0646\u0628\u0631".split("_"),weekdays:"\u0627\u0644\u0623\u062d\u062f_\u0627\u0644\u0625\u062a\u0646\u064a\u0646_\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621_\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621_\u0627\u0644\u062e\u0645\u064a\u0633_\u0627\u0644\u062c\u0645\u0639\u0629_\u0627\u0644\u0633\u0628\u062a".split("_"),weekdaysShort:"\u0627\u062d\u062f_\u0627\u062a\u0646\u064a\u0646_\u062b\u0644\u0627\u062b\u0627\u0621_\u0627\u0631\u0628\u0639\u0627\u0621_\u062e\u0645\u064a\u0633_\u062c\u0645\u0639\u0629_\u0633\u0628\u062a".split("_"),weekdaysMin:"\u062d_\u0646_\u062b_\u0631_\u062e_\u062c_\u0633".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[\u0627\u0644\u064a\u0648\u0645 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextDay:"[\u063a\u062f\u0627 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextWeek:"dddd [\u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastDay:"[\u0623\u0645\u0633 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastWeek:"dddd [\u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",sameElse:"L"},relativeTime:{future:"\u0641\u064a %s",past:"\u0645\u0646\u0630 %s",s:"\u062b\u0648\u0627\u0646",ss:"%d \u062b\u0627\u0646\u064a\u0629",m:"\u062f\u0642\u064a\u0642\u0629",mm:"%d \u062f\u0642\u0627\u0626\u0642",h:"\u0633\u0627\u0639\u0629",hh:"%d \u0633\u0627\u0639\u0627\u062a",d:"\u064a\u0648\u0645",dd:"%d \u0623\u064a\u0627\u0645",M:"\u0634\u0647\u0631",MM:"%d \u0623\u0634\u0647\u0631",y:"\u0633\u0646\u0629",yy:"%d \u0633\u0646\u0648\u0627\u062a"},week:{dow:0,doy:12}})}(n("wd/R"))},Qo9l:function(e,t,n){var i=n("2oRo");e.exports=i},RAwQ:function(e,t,n){!function(e){"use strict";function t(e,t,n,i){var r={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return t?r[n][0]:r[n][1]}function n(e){if(e=parseInt(e,10),isNaN(e))return!1;if(e<0)return!0;if(e<10)return 4<=e&&e<=7;if(e<100){var t=e%10;return n(0===t?e/10:t)}if(e<1e4){for(;e>=10;)e/=10;return n(e)}return n(e/=1e3)}e.defineLocale("lb",{months:"Januar_Februar_M\xe4erz_Abr\xebll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_M\xe9indeg_D\xebnschdeg_M\xebttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._M\xe9._D\xeb._M\xeb._Do._Fr._Sa.".split("_"),weekdaysMin:"So_M\xe9_D\xeb_M\xeb_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[G\xebschter um] LT",lastWeek:function(){switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:function(e){return n(e.substr(0,e.indexOf(" ")))?"a "+e:"an "+e},past:function(e){return n(e.substr(0,e.indexOf(" ")))?"viru "+e:"virun "+e},s:"e puer Sekonnen",ss:"%d Sekonnen",m:t,mm:"%d Minutten",h:t,hh:"%d Stonnen",d:t,dd:"%d Deeg",M:t,MM:"%d M\xe9int",y:t,yy:"%d Joer"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},RK3t:function(e,t,n){var i=n("0Dky"),r=n("xrYK"),s="".split;e.exports=i((function(){return!Object("z").propertyIsEnumerable(0)}))?function(e){return"String"==r(e)?s.call(e,""):Object(e)}:Object},RNIs:function(e,t,n){var i=n("tiKp"),r=n("fHMY"),s=n("m/L8"),o=i("unscopables"),a=Array.prototype;null==a[o]&&s.f(a,o,{configurable:!0,value:r(null)}),e.exports=function(e){a[o][e]=!0}},Rf2I:function(e,t,n){"use strict";n.d(t,"a",(function(){return A}));var i=n("s7LF"),r=n("LvDl"),s=n.n(r),o=n("2EZI"),a=n("Fgil"),c=n("aXbf"),l=n("8Y7J"),u=n("G0yt"),d=n("ajRT"),h=n("SVse"),f=n("NwgZ"),p=n("6+kj"),m=n("ANnk"),b=n("f69J"),g=n("EmSq"),_=n("ppaS");function y(e,t){if(1&e&&(l.Qb(0,10),l.Oc(1),l.Pb()),2&e){const e=l.ic();l.yb(1),l.Qc(" ",e.titleText," ")}}function v(e,t){if(1&e&&(l.Sb(0,"p"),l.Oc(1),l.Rb()),2&e){const e=l.ic();l.yb(1),l.Pc(e.message)}}const w=function(e){return{required:e}};function S(e,t){if(1&e&&(l.Sb(0,"label",18),l.Oc(1),l.Rb()),2&e){const e=l.ic().$implicit;l.pc("ngClass",l.uc(3,w,!0===(null==e?null:e.required)))("for",e.name),l.yb(1),l.Qc(" ",e.label," ")}}function M(e,t){if(1&e&&l.Nb(0,"input",19),2&e){const e=l.ic().$implicit;l.pc("type",e.type)("id",e.name)("name",e.name)("formControlName",e.name)}}function x(e,t){if(1&e&&l.Nb(0,"input",20),2&e){const e=l.ic().$implicit;l.pc("id",e.name)("name",e.name)("formControlName",e.name)}}function k(e,t){if(1&e&&(l.Sb(0,"option",24),l.Oc(1),l.Rb()),2&e){const e=l.ic(2).$implicit;l.pc("ngValue",null),l.yb(1),l.Qc(" ",null==e||null==e.typeConfig?null:e.typeConfig.placeholder," ")}}function D(e,t){if(1&e&&(l.Sb(0,"option",25),l.Oc(1),l.Rb()),2&e){const e=t.$implicit;l.pc("value",e.value),l.yb(1),l.Qc(" ",e.text," ")}}function T(e,t){if(1&e&&(l.Sb(0,"select",21),l.Mc(1,k,2,2,"option",22),l.Mc(2,D,2,2,"option",23),l.Rb()),2&e){const e=l.ic().$implicit;l.pc("id",e.name)("formControlName",e.name),l.yb(1),l.pc("ngIf",null==e||null==e.typeConfig?null:e.typeConfig.placeholder),l.yb(1),l.pc("ngForOf",null==e||null==e.typeConfig?null:e.typeConfig.options)}}function C(e,t){if(1&e&&l.Nb(0,"cd-select-badges",26),2&e){const e=l.ic().$implicit;l.pc("id",e.name)("data",e.value)("customBadges",null==e||null==e.typeConfig?null:e.typeConfig.customBadges)("options",null==e||null==e.typeConfig?null:e.typeConfig.options)("messages",null==e||null==e.typeConfig?null:e.typeConfig.messages)}}function O(e,t){if(1&e&&(l.Sb(0,"span",27),l.Oc(1),l.Rb()),2&e){const e=l.ic().$implicit,t=l.ic();l.yb(1),l.Qc(" ",t.getError(e)," ")}}const L=function(e,t){return{"cd-col-form-input":e,"col-sm-12":t}},R=function(){return["text","number"]};function E(e,t){if(1&e&&(l.Qb(0),l.Sb(1,"div"),l.Mc(2,S,2,5,"label",11),l.Sb(3,"div",12),l.Mc(4,M,1,4,"input",13),l.Mc(5,x,1,3,"input",14),l.Mc(6,T,3,4,"select",15),l.Mc(7,C,1,5,"cd-select-badges",16),l.Mc(8,O,2,1,"span",17),l.Rb(),l.Rb(),l.Pb()),2&e){const e=t.$implicit,n=l.ic(),i=l.Ac(4);l.yb(1),l.Bb("form-group row cd-",e.name,"-form-group"),l.yb(1),l.pc("ngIf",e.label),l.yb(1),l.pc("ngClass",l.vc(10,L,e.label,!e.label)),l.yb(1),l.pc("ngIf",l.tc(13,R).includes(e.type)),l.yb(1),l.pc("ngIf","binary"===e.type),l.yb(1),l.pc("ngIf","select"===e.type),l.yb(1),l.pc("ngIf","select-badges"===e.type),l.yb(1),l.pc("ngIf",n.formGroup.showError(e.name,i))}}let A=(()=>{class e{constructor(e,t,n,i){this.activeModal=e,this.formBuilder=t,this.formatter=n,this.dimlessBinaryPipe=i}ngOnInit(){this.createForm()}createForm(){const e={};this.fields.forEach(t=>{e[t.name]=this.createFormControl(t)}),this.formGroup=this.formBuilder.group(e)}createFormControl(e){let t=[];return s.a.isBoolean(e.required)&&e.required&&t.push(i.A.required),e.validators&&(t=t.concat(e.validators)),new i.h(s.a.defaultTo("binary"===e.type?this.dimlessBinaryPipe.transform(e.value):e.value,null),{validators:t})}getError(e){const t=this.formGroup.get(e.name).errors;return Object.keys(t).map(n=>this.getErrorMessage(n,t[n],e.errors)).join("
")}getErrorMessage(e,t,n){if(n){const t=n[e];if(t)return t}return["binaryMin","binaryMax"].includes(e)?t():"required"===e?"This field is required.":"An error occurred."}onSubmitForm(e){this.fields.filter(e=>"binary"===e.type).map(e=>e.name).forEach(t=>{const n=e[t];n&&(e[t]=this.formatter.toBytes(n))}),this.activeModal.close(),s.a.isFunction(this.onSubmit)&&this.onSubmit(e)}}return e.\u0275fac=function(t){return new(t||e)(l.Mb(u.a),l.Mb(o.a),l.Mb(c.a),l.Mb(a.a))},e.\u0275cmp=l.Gb({type:e,selectors:[["cd-form-modal"]],decls:10,vars:7,consts:[[3,"modalRef"],["class","modal-title",4,"ngIf"],[1,"modal-content"],["novalidate","",3,"formGroup"],["formDir","ngForm"],[1,"modal-body"],[4,"ngIf"],[4,"ngFor","ngForOf"],[1,"modal-footer"],[3,"form","submitText","submitActionEvent"],[1,"modal-title"],["class","cd-col-form-label",3,"ngClass","for",4,"ngIf"],[3,"ngClass"],["class","form-control",3,"type","id","name","formControlName",4,"ngIf"],["type","text","class","form-control","cdDimlessBinary","",3,"id","name","formControlName",4,"ngIf"],["class","form-control custom-select",3,"id","formControlName",4,"ngIf"],[3,"id","data","customBadges","options","messages",4,"ngIf"],["class","invalid-feedback",4,"ngIf"],[1,"cd-col-form-label",3,"ngClass","for"],[1,"form-control",3,"type","id","name","formControlName"],["type","text","cdDimlessBinary","",1,"form-control",3,"id","name","formControlName"],[1,"form-control","custom-select",3,"id","formControlName"],[3,"ngValue",4,"ngIf"],[3,"value",4,"ngFor","ngForOf"],[3,"ngValue"],[3,"value"],[3,"id","data","customBadges","options","messages"],[1,"invalid-feedback"]],template:function(e,t){1&e&&(l.Sb(0,"cd-modal",0),l.Mc(1,y,2,1,"ng-container",1),l.Qb(2,2),l.Sb(3,"form",3,4),l.Sb(5,"div",5),l.Mc(6,v,2,1,"p",6),l.Mc(7,E,9,14,"ng-container",7),l.Rb(),l.Sb(8,"div",8),l.Sb(9,"cd-form-button-panel",9),l.gc("submitActionEvent",(function(){return t.onSubmitForm(t.formGroup.value)})),l.Rb(),l.Rb(),l.Rb(),l.Pb(),l.Rb()),2&e&&(l.pc("modalRef",t.activeModal),l.yb(1),l.pc("ngIf",t.titleText),l.yb(2),l.pc("formGroup",t.formGroup),l.yb(3),l.pc("ngIf",t.message),l.yb(1),l.pc("ngForOf",t.fields),l.yb(2),l.pc("form",t.formGroup)("submitText",t.submitButtonText))},directives:[d.a,h.r,i.C,i.r,i.k,f.a,h.q,p.a,h.p,m.a,i.d,b.a,i.q,i.i,g.a,i.z,i.u,i.B,_.a],styles:[""]}),e})()},Rm1S:function(e,t,n){"use strict";var i=n("14Sl"),r=n("glrk"),s=n("UMSQ"),o=n("HYAF"),a=n("iqWW"),c=n("FMNM");i("match",1,(function(e,t,n){return[function(t){var n=o(this),i=null==t?void 0:t[e];return void 0!==i?i.call(t,n):new RegExp(t)[e](String(n))},function(e){var i=n(t,e,this);if(i.done)return i.value;var o=r(e),l=String(this);if(!o.global)return c(o,l);var u=o.unicode;o.lastIndex=0;for(var d,h=[],f=0;null!==(d=c(o,l));){var p=String(d[0]);h[f]=p,""===p&&(o.lastIndex=a(l,s(o.lastIndex),u)),f++}return 0===f?null:h}]}))},RnhZ:function(e,t,n){var i={"./af":"K/tc","./af.js":"K/tc","./ar":"jnO4","./ar-dz":"o1bE","./ar-dz.js":"o1bE","./ar-kw":"Qj4J","./ar-kw.js":"Qj4J","./ar-ly":"HP3h","./ar-ly.js":"HP3h","./ar-ma":"CoRJ","./ar-ma.js":"CoRJ","./ar-sa":"gjCT","./ar-sa.js":"gjCT","./ar-tn":"bYM6","./ar-tn.js":"bYM6","./ar.js":"jnO4","./az":"SFxW","./az.js":"SFxW","./be":"H8ED","./be.js":"H8ED","./bg":"hKrs","./bg.js":"hKrs","./bm":"p/rL","./bm.js":"p/rL","./bn":"kEOa","./bn-bd":"loYQ","./bn-bd.js":"loYQ","./bn.js":"kEOa","./bo":"0mo+","./bo.js":"0mo+","./br":"aIdf","./br.js":"aIdf","./bs":"JVSJ","./bs.js":"JVSJ","./ca":"1xZ4","./ca.js":"1xZ4","./cs":"PA2r","./cs.js":"PA2r","./cv":"A+xa","./cv.js":"A+xa","./cy":"l5ep","./cy.js":"l5ep","./da":"DxQv","./da.js":"DxQv","./de":"tGlX","./de-at":"s+uk","./de-at.js":"s+uk","./de-ch":"u3GI","./de-ch.js":"u3GI","./de.js":"tGlX","./dv":"WYrj","./dv.js":"WYrj","./el":"jUeY","./el.js":"jUeY","./en-au":"Dmvi","./en-au.js":"Dmvi","./en-ca":"OIYi","./en-ca.js":"OIYi","./en-gb":"Oaa7","./en-gb.js":"Oaa7","./en-ie":"4dOw","./en-ie.js":"4dOw","./en-il":"czMo","./en-il.js":"czMo","./en-in":"7C5Q","./en-in.js":"7C5Q","./en-nz":"b1Dy","./en-nz.js":"b1Dy","./en-sg":"t+mt","./en-sg.js":"t+mt","./eo":"Zduo","./eo.js":"Zduo","./es":"iYuL","./es-do":"CjzT","./es-do.js":"CjzT","./es-mx":"tbfe","./es-mx.js":"tbfe","./es-us":"Vclq","./es-us.js":"Vclq","./es.js":"iYuL","./et":"7BjC","./et.js":"7BjC","./eu":"D/JM","./eu.js":"D/JM","./fa":"jfSC","./fa.js":"jfSC","./fi":"gekB","./fi.js":"gekB","./fil":"1ppg","./fil.js":"1ppg","./fo":"ByF4","./fo.js":"ByF4","./fr":"nyYc","./fr-ca":"2fjn","./fr-ca.js":"2fjn","./fr-ch":"Dkky","./fr-ch.js":"Dkky","./fr.js":"nyYc","./fy":"cRix","./fy.js":"cRix","./ga":"USCx","./ga.js":"USCx","./gd":"9rRi","./gd.js":"9rRi","./gl":"iEDd","./gl.js":"iEDd","./gom-deva":"qvJo","./gom-deva.js":"qvJo","./gom-latn":"DKr+","./gom-latn.js":"DKr+","./gu":"4MV3","./gu.js":"4MV3","./he":"x6pH","./he.js":"x6pH","./hi":"3E1r","./hi.js":"3E1r","./hr":"S6ln","./hr.js":"S6ln","./hu":"WxRl","./hu.js":"WxRl","./hy-am":"1rYy","./hy-am.js":"1rYy","./id":"UDhR","./id.js":"UDhR","./is":"BVg3","./is.js":"BVg3","./it":"bpih","./it-ch":"bxKX","./it-ch.js":"bxKX","./it.js":"bpih","./ja":"B55N","./ja.js":"B55N","./jv":"tUCv","./jv.js":"tUCv","./ka":"IBtZ","./ka.js":"IBtZ","./kk":"bXm7","./kk.js":"bXm7","./km":"6B0Y","./km.js":"6B0Y","./kn":"PpIw","./kn.js":"PpIw","./ko":"Ivi+","./ko.js":"Ivi+","./ku":"JCF/","./ku.js":"JCF/","./ky":"lgnt","./ky.js":"lgnt","./lb":"RAwQ","./lb.js":"RAwQ","./lo":"sp3z","./lo.js":"sp3z","./lt":"JvlW","./lt.js":"JvlW","./lv":"uXwI","./lv.js":"uXwI","./me":"KTz0","./me.js":"KTz0","./mi":"aIsn","./mi.js":"aIsn","./mk":"aQkU","./mk.js":"aQkU","./ml":"AvvY","./ml.js":"AvvY","./mn":"lYtQ","./mn.js":"lYtQ","./mr":"Ob0Z","./mr.js":"Ob0Z","./ms":"6+QB","./ms-my":"ZAMP","./ms-my.js":"ZAMP","./ms.js":"6+QB","./mt":"G0Uy","./mt.js":"G0Uy","./my":"honF","./my.js":"honF","./nb":"bOMt","./nb.js":"bOMt","./ne":"OjkT","./ne.js":"OjkT","./nl":"+s0g","./nl-be":"2ykv","./nl-be.js":"2ykv","./nl.js":"+s0g","./nn":"uEye","./nn.js":"uEye","./oc-lnc":"Fnuy","./oc-lnc.js":"Fnuy","./pa-in":"8/+R","./pa-in.js":"8/+R","./pl":"jVdC","./pl.js":"jVdC","./pt":"8mBD","./pt-br":"0tRk","./pt-br.js":"0tRk","./pt.js":"8mBD","./ro":"lyxo","./ro.js":"lyxo","./ru":"lXzo","./ru.js":"lXzo","./sd":"Z4QM","./sd.js":"Z4QM","./se":"//9w","./se.js":"//9w","./si":"7aV9","./si.js":"7aV9","./sk":"e+ae","./sk.js":"e+ae","./sl":"gVVK","./sl.js":"gVVK","./sq":"yPMs","./sq.js":"yPMs","./sr":"zx6S","./sr-cyrl":"E+lV","./sr-cyrl.js":"E+lV","./sr.js":"zx6S","./ss":"Ur1D","./ss.js":"Ur1D","./sv":"X709","./sv.js":"X709","./sw":"dNwA","./sw.js":"dNwA","./ta":"PeUW","./ta.js":"PeUW","./te":"XLvN","./te.js":"XLvN","./tet":"V2x9","./tet.js":"V2x9","./tg":"Oxv6","./tg.js":"Oxv6","./th":"EOgW","./th.js":"EOgW","./tk":"Wv91","./tk.js":"Wv91","./tl-ph":"Dzi0","./tl-ph.js":"Dzi0","./tlh":"z3Vd","./tlh.js":"z3Vd","./tr":"DoHr","./tr.js":"DoHr","./tzl":"z1FC","./tzl.js":"z1FC","./tzm":"wQk9","./tzm-latn":"tT3J","./tzm-latn.js":"tT3J","./tzm.js":"wQk9","./ug-cn":"YRex","./ug-cn.js":"YRex","./uk":"raLr","./uk.js":"raLr","./ur":"UpQW","./ur.js":"UpQW","./uz":"Loxo","./uz-latn":"AQ68","./uz-latn.js":"AQ68","./uz.js":"Loxo","./vi":"KSF8","./vi.js":"KSF8","./x-pseudo":"/X5v","./x-pseudo.js":"/X5v","./yo":"fzPg","./yo.js":"fzPg","./zh-cn":"XDpg","./zh-cn.js":"XDpg","./zh-hk":"SatO","./zh-hk.js":"SatO","./zh-mo":"OmwH","./zh-mo.js":"OmwH","./zh-tw":"kOpN","./zh-tw.js":"kOpN"};function r(e){var t=s(e);return n(t)}function s(e){if(!n.o(i,e)){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}return i[e]}r.keys=function(){return Object.keys(i)},r.resolve=s,e.exports=r,r.id="RnhZ"},S6ln:function(e,t,n){!function(e){"use strict";function t(e,t,n){var i=e+" ";switch(n){case"ss":return i+(1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi");case"m":return t?"jedna minuta":"jedne minute";case"mm":return i+(1===e?"minuta":2===e||3===e||4===e?"minute":"minuta");case"h":return t?"jedan sat":"jednog sata";case"hh":return i+(1===e?"sat":2===e||3===e||4===e?"sata":"sati");case"dd":return i+(1===e?"dan":"dana");case"MM":return i+(1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci");case"yy":return i+(1===e?"godina":2===e||3===e||4===e?"godine":"godina")}}e.defineLocale("hr",{months:{format:"sije\u010dnja_velja\u010de_o\u017eujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"sije\u010danj_velja\u010da_o\u017eujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._o\u017eu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_\u010detvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._\u010det._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_\u010de_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM YYYY",LLL:"Do MMMM YYYY H:mm",LLLL:"dddd, Do MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[ju\u010der u] LT",lastWeek:function(){switch(this.day()){case 0:return"[pro\u0161lu] [nedjelju] [u] LT";case 3:return"[pro\u0161lu] [srijedu] [u] LT";case 6:return"[pro\u0161le] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[pro\u0161li] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:t,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(n("wd/R"))},S7zO:function(e,t,n){"use strict";n.d(t,"a",(function(){return g}));var i=n("LvDl"),r=n.n(i),s=n("oxzT"),o=(n("vCyI"),n("jKX/"),n("8Y7J")),a=n("SVse"),c=n("iInd"),l=n("G0yt");const u=function(e){return{disabled:e}},d=function(e){return[e]};function h(e,t){if(1&e){const e=o.Tb();o.Qb(0),o.Sb(1,"button",3),o.gc("click",(function(){o.Dc(e);const t=o.ic();return t.useClickAction(t.currentAction)})),o.Nb(2,"i",4),o.Sb(3,"span"),o.Oc(4),o.Rb(),o.Rb(),o.Pb()}if(2&e){const e=o.ic();o.yb(1),o.Bb("btn btn-",e.btnColor,""),o.qc("title",e.useDisableDesc(e.currentAction)),o.pc("ngClass",o.uc(9,u,e.disableSelectionAction(e.currentAction)))("routerLink",e.useRouterLink(e.currentAction))("preserveFragment",e.currentAction.preserveFragment?"":null),o.yb(1),o.pc("ngClass",o.uc(11,d,e.currentAction.icon)),o.yb(2),o.Pc(e.currentAction.name)}}function f(e,t){if(1&e&&(o.Qb(0),o.Oc(1),o.Pb()),2&e){const e=o.ic(2);o.yb(1),o.Qc("",e.dropDownOnly," ")}}function p(e,t){1&e&&o.Nb(0,"span",10)}function m(e,t){if(1&e){const e=o.Tb();o.Qb(0),o.Sb(1,"button",11),o.gc("click",(function(){o.Dc(e);const n=t.$implicit;return o.ic(2).useClickAction(n)})),o.Nb(2,"i",4),o.Sb(3,"span"),o.Oc(4),o.Rb(),o.Rb(),o.Pb()}if(2&e){const e=t.$implicit,n=o.ic(2);o.yb(1),o.Ab(n.toClassName(e)),o.qc("title",n.useDisableDesc(e)),o.pc("routerLink",n.useRouterLink(e))("preserveFragment",e.preserveFragment?"":null)("disabled",n.disableSelectionAction(e)),o.yb(1),o.pc("ngClass",o.uc(9,d,e.icon)),o.yb(2),o.Pc(e.name)}}function b(e,t){if(1&e&&(o.Sb(0,"div",5),o.Sb(1,"button",6),o.Mc(2,f,2,1,"ng-container",1),o.Mc(3,p,1,0,"span",7),o.Rb(),o.Sb(4,"div",8),o.Mc(5,m,5,11,"ng-container",9),o.Rb(),o.Rb()),2&e){const e=o.ic();o.yb(1),o.Bb("btn btn-",e.btnColor," dropdown-toggle-split"),o.yb(1),o.pc("ngIf",e.dropDownOnly),o.yb(1),o.pc("ngIf",!e.dropDownOnly),o.yb(2),o.pc("ngForOf",e.dropDownActions)}}let g=(()=>{class e{constructor(){this.btnColor="accent",this.dropDownActions=[],this.icons=s.a}ngOnInit(){this.removeActionsWithNoPermissions(),this.onSelectionChange()}ngOnChanges(e){e.selection&&this.onSelectionChange()}onSelectionChange(){this.updateDropDownActions(),this.updateCurrentAction()}toClassName(e){return e.name.replace(/ /g,"-").replace(/[^a-z-]/gi,"").toLowerCase()}removeActionsWithNoPermissions(){if(!this.permission)return void(this.tableActions=[]);const e=Object.keys(this.permission).filter(e=>this.permission[e]);this.tableActions=this.tableActions.filter(t=>e.includes(t.permission))}updateDropDownActions(){this.dropDownActions=this.tableActions.filter(e=>e.visible?e.visible(this.selection):e)}updateCurrentAction(){if(this.dropDownOnly)return void(this.currentAction=void 0);let e=this.dropDownActions.find(e=>this.showableAction(e));!e&&this.dropDownActions.length>0&&(e=this.dropDownActions[0]),this.currentAction=e}showableAction(e){const t=e.canBePrimary,n=this.selection.hasSingleSelection,i="create"===e.permission?!n:n;return t&&t(this.selection)||!t&&i}useRouterLink(e){if(e.routerLink&&!this.disableSelectionAction(e))return r.a.isString(e.routerLink)?e.routerLink:e.routerLink()}disableSelectionAction(e){const t=e.disable;if(t)return Boolean(t(this.selection));const n=e.permission,i=this.selection.hasSingleSelection&&this.selection.first();return Boolean(["update","delete"].includes(n)&&(!i||i.cdExecuting))}useClickAction(e){return!this.disableSelectionAction(e)&&e.click&&e.click()}useDisableDesc(e){if(e.disable){const t=e.disable(this.selection);return r.a.isString(t)?t:void 0}}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=o.Gb({type:e,selectors:[["cd-table-actions"]],inputs:{permission:"permission",selection:"selection",tableActions:"tableActions",btnColor:"btnColor",dropDownOnly:"dropDownOnly"},features:[o.wb],decls:3,vars:2,consts:[[1,"btn-group"],[4,"ngIf"],["class","btn-group","ngbDropdown","","role","group","aria-label","Button group with nested dropdown",4,"ngIf"],["type","button",3,"title","ngClass","routerLink","preserveFragment","click"],[3,"ngClass"],["ngbDropdown","","role","group","aria-label","Button group with nested dropdown",1,"btn-group"],["ngbDropdownToggle",""],["class","sr-only",4,"ngIf"],["ngbDropdownMenu","",1,"dropdown-menu"],[4,"ngFor","ngForOf"],[1,"sr-only"],["ngbDropdownItem","",3,"title","routerLink","preserveFragment","disabled","click"]],template:function(e,t){1&e&&(o.Sb(0,"div",0),o.Mc(1,h,5,13,"ng-container",1),o.Mc(2,b,6,6,"div",2),o.Rb()),2&e&&(o.yb(1),o.pc("ngIf",t.currentAction),o.yb(1),o.pc("ngIf",t.dropDownActions.length>1))},directives:[a.r,a.p,c.f,l.i,l.m,l.k,a.q,l.j],styles:["button.disabled[_ngcontent-%COMP%]{cursor:default!important;pointer-events:auto}"]}),e})()},SFxW:function(e,t,n){!function(e){"use strict";var t={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-\xfcnc\xfc",4:"-\xfcnc\xfc",100:"-\xfcnc\xfc",6:"-nc\u0131",9:"-uncu",10:"-uncu",30:"-uncu",60:"-\u0131nc\u0131",90:"-\u0131nc\u0131"};e.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ert\u0259si_\xc7\u0259r\u015f\u0259nb\u0259 ax\u015fam\u0131_\xc7\u0259r\u015f\u0259nb\u0259_C\xfcm\u0259 ax\u015fam\u0131_C\xfcm\u0259_\u015e\u0259nb\u0259".split("_"),weekdaysShort:"Baz_BzE_\xc7Ax_\xc7\u0259r_CAx_C\xfcm_\u015e\u0259n".split("_"),weekdaysMin:"Bz_BE_\xc7A_\xc7\u0259_CA_C\xfc_\u015e\u0259".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bug\xfcn saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[g\u0259l\u0259n h\u0259ft\u0259] dddd [saat] LT",lastDay:"[d\xfcn\u0259n] LT",lastWeek:"[ke\xe7\u0259n h\u0259ft\u0259] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s \u0259vv\u0259l",s:"bir ne\xe7\u0259 saniy\u0259",ss:"%d saniy\u0259",m:"bir d\u0259qiq\u0259",mm:"%d d\u0259qiq\u0259",h:"bir saat",hh:"%d saat",d:"bir g\xfcn",dd:"%d g\xfcn",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gec\u0259|s\u0259h\u0259r|g\xfcnd\xfcz|ax\u015fam/,isPM:function(e){return/^(g\xfcnd\xfcz|ax\u015fam)$/.test(e)},meridiem:function(e,t,n){return e<4?"gec\u0259":e<12?"s\u0259h\u0259r":e<17?"g\xfcnd\xfcz":"ax\u015fam"},dayOfMonthOrdinalParse:/\d{1,2}-(\u0131nc\u0131|inci|nci|\xfcnc\xfc|nc\u0131|uncu)/,ordinal:function(e){if(0===e)return e+"-\u0131nc\u0131";var n=e%10;return e+(t[n]||t[e%100-n]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(n("wd/R"))},STAE:function(e,t,n){var i=n("LQDL"),r=n("0Dky");e.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())||!Symbol.sham&&i&&i<41}))},SVse:function(e,t,n){"use strict";n.d(t,"a",(function(){return v})),n.d(t,"b",(function(){return Ae})),n.d(t,"c",(function(){return Ge})),n.d(t,"d",(function(){return c})),n.d(t,"e",(function(){return Fe})),n.d(t,"f",(function(){return Ve})),n.d(t,"g",(function(){return C})),n.d(t,"h",(function(){return S})),n.d(t,"i",(function(){return ze})),n.d(t,"j",(function(){return $e})),n.d(t,"k",(function(){return He})),n.d(t,"l",(function(){return d})),n.d(t,"m",(function(){return M})),n.d(t,"n",(function(){return _})),n.d(t,"o",(function(){return Ie})),n.d(t,"p",(function(){return me})),n.d(t,"q",(function(){return ge})),n.d(t,"r",(function(){return ye})),n.d(t,"s",(function(){return De})),n.d(t,"t",(function(){return Me})),n.d(t,"u",(function(){return xe})),n.d(t,"v",(function(){return ke})),n.d(t,"w",(function(){return Te})),n.d(t,"x",(function(){return w})),n.d(t,"y",(function(){return Be})),n.d(t,"z",(function(){return l})),n.d(t,"A",(function(){return je})),n.d(t,"B",(function(){return O})),n.d(t,"C",(function(){return Ne})),n.d(t,"D",(function(){return Ke})),n.d(t,"E",(function(){return Q})),n.d(t,"F",(function(){return A})),n.d(t,"G",(function(){return E})),n.d(t,"H",(function(){return I})),n.d(t,"I",(function(){return Qe})),n.d(t,"J",(function(){return a})),n.d(t,"K",(function(){return Je})),n.d(t,"L",(function(){return s})),n.d(t,"M",(function(){return pe})),n.d(t,"N",(function(){return o}));var i=n("8Y7J");let r=null;function s(){return r}function o(e){r||(r=e)}class a{}const c=new i.r("DocumentToken");let l=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:u,token:e,providedIn:"platform"}),e})();function u(){return Object(i.dc)(h)}const d=new i.r("Location Initialized");let h=(()=>{class e extends l{constructor(e){super(),this._doc=e,this._init()}_init(){this.location=s().getLocation(),this._history=s().getHistory()}getBaseHrefFromDOM(){return s().getBaseHref(this._doc)}onPopState(e){s().getGlobalEventTarget(this._doc,"window").addEventListener("popstate",e,!1)}onHashChange(e){s().getGlobalEventTarget(this._doc,"window").addEventListener("hashchange",e,!1)}get href(){return this.location.href}get protocol(){return this.location.protocol}get hostname(){return this.location.hostname}get port(){return this.location.port}get pathname(){return this.location.pathname}get search(){return this.location.search}get hash(){return this.location.hash}set pathname(e){this.location.pathname=e}pushState(e,t,n){f()?this._history.pushState(e,t,n):this.location.hash=n}replaceState(e,t,n){f()?this._history.replaceState(e,t,n):this.location.hash=n}forward(){this._history.forward()}back(){this._history.back()}getState(){return this._history.state}}return e.\u0275fac=function(t){return new(t||e)(i.dc(c))},e.\u0275prov=Object(i.Ib)({factory:p,token:e,providedIn:"platform"}),e})();function f(){return!!window.history.pushState}function p(){return new h(Object(i.dc)(c))}function m(e,t){if(0==e.length)return t;if(0==t.length)return e;let n=0;return e.endsWith("/")&&n++,t.startsWith("/")&&n++,2==n?e+t.substring(1):1==n?e+t:e+"/"+t}function b(e){const t=e.match(/#|\?|$/),n=t&&t.index||e.length;return e.slice(0,n-("/"===e[n-1]?1:0))+e.slice(n)}function g(e){return e&&"?"!==e[0]?"?"+e:e}let _=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(i.Ib)({factory:y,token:e,providedIn:"root"}),e})();function y(e){const t=Object(i.dc)(c).location;return new w(Object(i.dc)(l),t&&t.origin||"")}const v=new i.r("appBaseHref");let w=(()=>{class e extends _{constructor(e,t){if(super(),this._platformLocation=e,null==t&&(t=this._platformLocation.getBaseHrefFromDOM()),null==t)throw new Error("No base href set. Please provide a value for the APP_BASE_HREF token or add a base element to the document.");this._baseHref=t}onPopState(e){this._platformLocation.onPopState(e),this._platformLocation.onHashChange(e)}getBaseHref(){return this._baseHref}prepareExternalUrl(e){return m(this._baseHref,e)}path(e=!1){const t=this._platformLocation.pathname+g(this._platformLocation.search),n=this._platformLocation.hash;return n&&e?`${t}${n}`:t}pushState(e,t,n,i){const r=this.prepareExternalUrl(n+g(i));this._platformLocation.pushState(e,t,r)}replaceState(e,t,n,i){const r=this.prepareExternalUrl(n+g(i));this._platformLocation.replaceState(e,t,r)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}}return e.\u0275fac=function(t){return new(t||e)(i.dc(l),i.dc(v,8))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})(),S=(()=>{class e extends _{constructor(e,t){super(),this._platformLocation=e,this._baseHref="",null!=t&&(this._baseHref=t)}onPopState(e){this._platformLocation.onPopState(e),this._platformLocation.onHashChange(e)}getBaseHref(){return this._baseHref}path(e=!1){let t=this._platformLocation.hash;return null==t&&(t="#"),t.length>0?t.substring(1):t}prepareExternalUrl(e){const t=m(this._baseHref,e);return t.length>0?"#"+t:t}pushState(e,t,n,i){let r=this.prepareExternalUrl(n+g(i));0==r.length&&(r=this._platformLocation.pathname),this._platformLocation.pushState(e,t,r)}replaceState(e,t,n,i){let r=this.prepareExternalUrl(n+g(i));0==r.length&&(r=this._platformLocation.pathname),this._platformLocation.replaceState(e,t,r)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}}return e.\u0275fac=function(t){return new(t||e)(i.dc(l),i.dc(v,8))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})(),M=(()=>{class e{constructor(e,t){this._subject=new i.o,this._urlChangeListeners=[],this._platformStrategy=e;const n=this._platformStrategy.getBaseHref();this._platformLocation=t,this._baseHref=b(k(n)),this._platformStrategy.onPopState(e=>{this._subject.emit({url:this.path(!0),pop:!0,state:e.state,type:e.type})})}path(e=!1){return this.normalize(this._platformStrategy.path(e))}getState(){return this._platformLocation.getState()}isCurrentPathEqualTo(e,t=""){return this.path()==this.normalize(e+g(t))}normalize(t){return e.stripTrailingSlash(function(e,t){return e&&t.startsWith(e)?t.substring(e.length):t}(this._baseHref,k(t)))}prepareExternalUrl(e){return e&&"/"!==e[0]&&(e="/"+e),this._platformStrategy.prepareExternalUrl(e)}go(e,t="",n=null){this._platformStrategy.pushState(n,"",e,t),this._notifyUrlChangeListeners(this.prepareExternalUrl(e+g(t)),n)}replaceState(e,t="",n=null){this._platformStrategy.replaceState(n,"",e,t),this._notifyUrlChangeListeners(this.prepareExternalUrl(e+g(t)),n)}forward(){this._platformStrategy.forward()}back(){this._platformStrategy.back()}onUrlChange(e){this._urlChangeListeners.push(e),this._urlChangeSubscription||(this._urlChangeSubscription=this.subscribe(e=>{this._notifyUrlChangeListeners(e.url,e.state)}))}_notifyUrlChangeListeners(e="",t){this._urlChangeListeners.forEach(n=>n(e,t))}subscribe(e,t,n){return this._subject.subscribe({next:e,error:t,complete:n})}}return e.\u0275fac=function(t){return new(t||e)(i.dc(_),i.dc(l))},e.normalizeQueryParams=g,e.joinWithSlash=m,e.stripTrailingSlash=b,e.\u0275prov=Object(i.Ib)({factory:x,token:e,providedIn:"root"}),e})();function x(){return new M(Object(i.dc)(_),Object(i.dc)(l))}function k(e){return e.replace(/\/index.html$/,"")}var D=function(e){return e[e.Decimal=0]="Decimal",e[e.Percent=1]="Percent",e[e.Currency=2]="Currency",e[e.Scientific=3]="Scientific",e}({}),T=function(e){return e[e.Zero=0]="Zero",e[e.One=1]="One",e[e.Two=2]="Two",e[e.Few=3]="Few",e[e.Many=4]="Many",e[e.Other=5]="Other",e}({}),C=function(e){return e[e.Format=0]="Format",e[e.Standalone=1]="Standalone",e}({}),O=function(e){return e[e.Narrow=0]="Narrow",e[e.Abbreviated=1]="Abbreviated",e[e.Wide=2]="Wide",e[e.Short=3]="Short",e}({}),L=function(e){return e[e.Short=0]="Short",e[e.Medium=1]="Medium",e[e.Long=2]="Long",e[e.Full=3]="Full",e}({}),R=function(e){return e[e.Decimal=0]="Decimal",e[e.Group=1]="Group",e[e.List=2]="List",e[e.PercentSign=3]="PercentSign",e[e.PlusSign=4]="PlusSign",e[e.MinusSign=5]="MinusSign",e[e.Exponential=6]="Exponential",e[e.SuperscriptingExponent=7]="SuperscriptingExponent",e[e.PerMille=8]="PerMille",e[e[1/0]=9]="Infinity",e[e.NaN=10]="NaN",e[e.TimeSeparator=11]="TimeSeparator",e[e.CurrencyDecimal=12]="CurrencyDecimal",e[e.CurrencyGroup=13]="CurrencyGroup",e}({});function E(e,t,n){const r=Object(i.ib)(e),s=H([r[i.Z.DayPeriodsFormat],r[i.Z.DayPeriodsStandalone]],t);return H(s,n)}function A(e,t,n){const r=Object(i.ib)(e),s=H([r[i.Z.DaysFormat],r[i.Z.DaysStandalone]],t);return H(s,n)}function I(e,t,n){const r=Object(i.ib)(e),s=H([r[i.Z.MonthsFormat],r[i.Z.MonthsStandalone]],t);return H(s,n)}function P(e,t){return H(Object(i.ib)(e)[i.Z.DateFormat],t)}function j(e,t){return H(Object(i.ib)(e)[i.Z.TimeFormat],t)}function N(e,t){return H(Object(i.ib)(e)[i.Z.DateTimeFormat],t)}function F(e,t){const n=Object(i.ib)(e),r=n[i.Z.NumberSymbols][t];if(void 0===r){if(t===R.CurrencyDecimal)return n[i.Z.NumberSymbols][R.Decimal];if(t===R.CurrencyGroup)return n[i.Z.NumberSymbols][R.Group]}return r}function Y(e,t){return Object(i.ib)(e)[i.Z.NumberFormats][t]}const z=i.lb;function $(e){if(!e[i.Z.ExtraData])throw new Error(`Missing extra locale data for the locale "${e[i.Z.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`)}function H(e,t){for(let n=t;n>-1;n--)if(void 0!==e[n])return e[n];throw new Error("Locale data API: locale data undefined")}function W(e){const[t,n]=e.split(":");return{hours:+t,minutes:+n}}const V=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,B={},U=/((?:[^GyMLwWdEabBhHmsSzZO']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;var q=function(e){return e[e.Short=0]="Short",e[e.ShortGMT=1]="ShortGMT",e[e.Long=2]="Long",e[e.Extended=3]="Extended",e}({}),G=function(e){return e[e.FullYear=0]="FullYear",e[e.Month=1]="Month",e[e.Date=2]="Date",e[e.Hours=3]="Hours",e[e.Minutes=4]="Minutes",e[e.Seconds=5]="Seconds",e[e.FractionalSeconds=6]="FractionalSeconds",e[e.Day=7]="Day",e}({}),J=function(e){return e[e.DayPeriods=0]="DayPeriods",e[e.Days=1]="Days",e[e.Months=2]="Months",e[e.Eras=3]="Eras",e}({});function Q(e,t,n,r){let s=function(e){if(se(e))return e;if("number"==typeof e&&!isNaN(e))return new Date(e);if("string"==typeof e){e=e.trim();const t=parseFloat(e);if(!isNaN(e-t))return new Date(t);if(/^(\d{4}-\d{1,2}-\d{1,2})$/.test(e)){const[t,n,i]=e.split("-").map(e=>+e);return new Date(t,n-1,i)}let n;if(n=e.match(V))return function(e){const t=new Date(0);let n=0,i=0;const r=e[8]?t.setUTCFullYear:t.setFullYear,s=e[8]?t.setUTCHours:t.setHours;e[9]&&(n=Number(e[9]+e[10]),i=Number(e[9]+e[11])),r.call(t,Number(e[1]),Number(e[2])-1,Number(e[3]));const o=Number(e[4]||0)-n,a=Number(e[5]||0)-i,c=Number(e[6]||0),l=Math.round(1e3*parseFloat("0."+(e[7]||0)));return s.call(t,o,a,c,l),t}(n)}const t=new Date(e);if(!se(t))throw new Error(`Unable to convert "${e}" into a date`);return t}(e);t=function e(t,n){const r=function(e){return Object(i.ib)(e)[i.Z.LocaleId]}(t);if(B[r]=B[r]||{},B[r][n])return B[r][n];let s="";switch(n){case"shortDate":s=P(t,L.Short);break;case"mediumDate":s=P(t,L.Medium);break;case"longDate":s=P(t,L.Long);break;case"fullDate":s=P(t,L.Full);break;case"shortTime":s=j(t,L.Short);break;case"mediumTime":s=j(t,L.Medium);break;case"longTime":s=j(t,L.Long);break;case"fullTime":s=j(t,L.Full);break;case"short":const n=e(t,"shortTime"),i=e(t,"shortDate");s=K(N(t,L.Short),[n,i]);break;case"medium":const r=e(t,"mediumTime"),o=e(t,"mediumDate");s=K(N(t,L.Medium),[r,o]);break;case"long":const a=e(t,"longTime"),c=e(t,"longDate");s=K(N(t,L.Long),[a,c]);break;case"full":const l=e(t,"fullTime"),u=e(t,"fullDate");s=K(N(t,L.Full),[l,u])}return s&&(B[r][n]=s),s}(n,t)||t;let o,a=[];for(;t;){if(o=U.exec(t),!o){a.push(t);break}{a=a.concat(o.slice(1));const e=a.pop();if(!e)break;t=e}}let c=s.getTimezoneOffset();r&&(c=re(r,c),s=function(e,t,n){const i=e.getTimezoneOffset();return function(e,t){return(e=new Date(e.getTime())).setMinutes(e.getMinutes()+t),e}(e,-1*(re(t,i)-i))}(s,r));let l="";return a.forEach(e=>{const t=function(e){if(ie[e])return ie[e];let t;switch(e){case"G":case"GG":case"GGG":t=ee(J.Eras,O.Abbreviated);break;case"GGGG":t=ee(J.Eras,O.Wide);break;case"GGGGG":t=ee(J.Eras,O.Narrow);break;case"y":t=X(G.FullYear,1,0,!1,!0);break;case"yy":t=X(G.FullYear,2,0,!0,!0);break;case"yyy":t=X(G.FullYear,3,0,!1,!0);break;case"yyyy":t=X(G.FullYear,4,0,!1,!0);break;case"M":case"L":t=X(G.Month,1,1);break;case"MM":case"LL":t=X(G.Month,2,1);break;case"MMM":t=ee(J.Months,O.Abbreviated);break;case"MMMM":t=ee(J.Months,O.Wide);break;case"MMMMM":t=ee(J.Months,O.Narrow);break;case"LLL":t=ee(J.Months,O.Abbreviated,C.Standalone);break;case"LLLL":t=ee(J.Months,O.Wide,C.Standalone);break;case"LLLLL":t=ee(J.Months,O.Narrow,C.Standalone);break;case"w":t=ne(1);break;case"ww":t=ne(2);break;case"W":t=ne(1,!0);break;case"d":t=X(G.Date,1);break;case"dd":t=X(G.Date,2);break;case"E":case"EE":case"EEE":t=ee(J.Days,O.Abbreviated);break;case"EEEE":t=ee(J.Days,O.Wide);break;case"EEEEE":t=ee(J.Days,O.Narrow);break;case"EEEEEE":t=ee(J.Days,O.Short);break;case"a":case"aa":case"aaa":t=ee(J.DayPeriods,O.Abbreviated);break;case"aaaa":t=ee(J.DayPeriods,O.Wide);break;case"aaaaa":t=ee(J.DayPeriods,O.Narrow);break;case"b":case"bb":case"bbb":t=ee(J.DayPeriods,O.Abbreviated,C.Standalone,!0);break;case"bbbb":t=ee(J.DayPeriods,O.Wide,C.Standalone,!0);break;case"bbbbb":t=ee(J.DayPeriods,O.Narrow,C.Standalone,!0);break;case"B":case"BB":case"BBB":t=ee(J.DayPeriods,O.Abbreviated,C.Format,!0);break;case"BBBB":t=ee(J.DayPeriods,O.Wide,C.Format,!0);break;case"BBBBB":t=ee(J.DayPeriods,O.Narrow,C.Format,!0);break;case"h":t=X(G.Hours,1,-12);break;case"hh":t=X(G.Hours,2,-12);break;case"H":t=X(G.Hours,1);break;case"HH":t=X(G.Hours,2);break;case"m":t=X(G.Minutes,1);break;case"mm":t=X(G.Minutes,2);break;case"s":t=X(G.Seconds,1);break;case"ss":t=X(G.Seconds,2);break;case"S":t=X(G.FractionalSeconds,1);break;case"SS":t=X(G.FractionalSeconds,2);break;case"SSS":t=X(G.FractionalSeconds,3);break;case"Z":case"ZZ":case"ZZZ":t=te(q.Short);break;case"ZZZZZ":t=te(q.Extended);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":t=te(q.ShortGMT);break;case"OOOO":case"ZZZZ":case"zzzz":t=te(q.Long);break;default:return null}return ie[e]=t,t}(e);l+=t?t(s,n,c):"''"===e?"'":e.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),l}function K(e,t){return t&&(e=e.replace(/\{([^}]+)}/g,(function(e,n){return null!=t&&n in t?t[n]:e}))),e}function Z(e,t,n="-",i,r){let s="";(e<0||r&&e<=0)&&(r?e=1-e:(e=-e,s=n));let o=String(e);for(;o.length0||a>-n)&&(a+=n),e===G.Hours)0===a&&-12===n&&(a=12);else if(e===G.FractionalSeconds)return c=t,Z(a,3).substr(0,c);var c;const l=F(o,R.MinusSign);return Z(a,t,l,i,r)}}function ee(e,t,n=C.Format,r=!1){return function(s,o){return function(e,t,n,r,s,o){switch(n){case J.Months:return I(t,s,r)[e.getMonth()];case J.Days:return A(t,s,r)[e.getDay()];case J.DayPeriods:const a=e.getHours(),c=e.getMinutes();if(o){const e=function(e){const t=Object(i.ib)(e);return $(t),(t[i.Z.ExtraData][2]||[]).map(e=>"string"==typeof e?W(e):[W(e[0]),W(e[1])])}(t),n=function(e,t,n){const r=Object(i.ib)(e);$(r);const s=H([r[i.Z.ExtraData][0],r[i.Z.ExtraData][1]],t)||[];return H(s,n)||[]}(t,s,r),o=e.findIndex(e=>{if(Array.isArray(e)){const[t,n]=e,i=a>=t.hours&&c>=t.minutes,r=a0?Math.floor(r/60):Math.ceil(r/60);switch(e){case q.Short:return(r>=0?"+":"")+Z(o,2,s)+Z(Math.abs(r%60),2,s);case q.ShortGMT:return"GMT"+(r>=0?"+":"")+Z(o,1,s);case q.Long:return"GMT"+(r>=0?"+":"")+Z(o,2,s)+":"+Z(Math.abs(r%60),2,s);case q.Extended:return 0===i?"Z":(r>=0?"+":"")+Z(o,2,s)+":"+Z(Math.abs(r%60),2,s);default:throw new Error(`Unknown zone width "${e}"`)}}}function ne(e,t=!1){return function(n,i){let r;if(t){const e=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,t=n.getDate();r=1+Math.floor((t+e)/7)}else{const e=(s=n,new Date(s.getFullYear(),s.getMonth(),s.getDate()+(4-s.getDay()))),t=function(e){const t=new Date(e,0,1).getDay();return new Date(e,0,1+(t<=4?4:11)-t)}(e.getFullYear()),i=e.getTime()-t.getTime();r=1+Math.round(i/6048e5)}var s;return Z(r,e,F(i,R.MinusSign))}}const ie={};function re(e,t){e=e.replace(/:/g,"");const n=Date.parse("Jan 01, 1970 00:00:00 "+e)/6e4;return isNaN(n)?t:n}function se(e){return e instanceof Date&&!isNaN(e.valueOf())}const oe=/^(\d+)?\.((\d+)(-(\d+))?)?$/,ae=".",ce="0";function le(e,t,n,i,r,s,o=!1){let a="",c=!1;if(isFinite(e)){let l=function(e){let t,n,i,r,s,o=Math.abs(e)+"",a=0;for((n=o.indexOf(ae))>-1&&(o=o.replace(ae,"")),(i=o.search(/e/i))>0?(n<0&&(n=i),n+=+o.slice(i+1),o=o.substring(0,i)):n<0&&(n=o.length),i=0;o.charAt(i)===ce;i++);if(i===(s=o.length))t=[0],n=1;else{for(s--;o.charAt(s)===ce;)s--;for(n-=i,t=[],r=0;i<=s;i++,r++)t[r]=Number(o.charAt(i))}return n>22&&(t=t.splice(0,21),a=n-1,n=1),{digits:t,exponent:a,integerLen:n}}(e);o&&(l=function(e){if(0===e.digits[0])return e;const t=e.digits.length-e.integerLen;return e.exponent?e.exponent+=2:(0===t?e.digits.push(0,0):1===t&&e.digits.push(0),e.integerLen+=2),e}(l));let u=t.minInt,d=t.minFrac,h=t.maxFrac;if(s){const e=s.match(oe);if(null===e)throw new Error(s+" is not a valid digit info");const t=e[1],n=e[3],i=e[5];null!=t&&(u=de(t)),null!=n&&(d=de(n)),null!=i?h=de(i):null!=n&&d>h&&(h=d)}!function(e,t,n){if(t>n)throw new Error(`The minimum number of digits after fraction (${t}) is higher than the maximum (${n}).`);let i=e.digits,r=i.length-e.integerLen;const s=Math.min(Math.max(t,r),n);let o=s+e.integerLen,a=i[o];if(o>0){i.splice(Math.max(e.integerLen,o));for(let e=o;e=5)if(o-1<0){for(let t=0;t>o;t--)i.unshift(0),e.integerLen++;i.unshift(1),e.integerLen++}else i[o-1]++;for(;r=l?i.pop():c=!1),t>=10?1:0}),0);u&&(i.unshift(u),e.integerLen++)}(l,d,h);let f=l.digits,p=l.integerLen;const m=l.exponent;let b=[];for(c=f.every(e=>!e);p0?b=f.splice(p,f.length):(b=f,f=[0]);const g=[];for(f.length>=t.lgSize&&g.unshift(f.splice(-t.lgSize,f.length).join(""));f.length>t.gSize;)g.unshift(f.splice(-t.gSize,f.length).join(""));f.length&&g.unshift(f.join("")),a=g.join(F(n,i)),b.length&&(a+=F(n,r)+b.join("")),m&&(a+=F(n,R.Exponential)+"+"+m)}else a=F(n,R.Infinity);return a=e<0&&!c?t.negPre+a+t.negSuf:t.posPre+a+t.posSuf,a}function ue(e,t="-"){const n={minInt:1,minFrac:0,maxFrac:0,posPre:"",posSuf:"",negPre:"",negSuf:"",gSize:0,lgSize:0},i=e.split(";"),r=i[0],s=i[1],o=-1!==r.indexOf(ae)?r.split(ae):[r.substring(0,r.lastIndexOf(ce)+1),r.substring(r.lastIndexOf(ce)+1)],a=o[0],c=o[1]||"";n.posPre=a.substr(0,a.indexOf("#"));for(let u=0;u{class e extends he{constructor(e){super(),this.locale=e}getPluralCategory(e,t){switch(z(t||this.locale)(e)){case T.Zero:return"zero";case T.One:return"one";case T.Two:return"two";case T.Few:return"few";case T.Many:return"many";default:return"other"}}}return e.\u0275fac=function(t){return new(t||e)(i.dc(i.v))},e.\u0275prov=i.Ib({token:e,factory:e.\u0275fac}),e})();function pe(e,t){t=encodeURIComponent(t);for(const n of e.split(";")){const e=n.indexOf("="),[i,r]=-1==e?[n,""]:[n.slice(0,e),n.slice(e+1)];if(i.trim()===t)return decodeURIComponent(r)}return null}let me=(()=>{class e{constructor(e,t,n,i){this._iterableDiffers=e,this._keyValueDiffers=t,this._ngEl=n,this._renderer=i,this._iterableDiffer=null,this._keyValueDiffer=null,this._initialClasses=[],this._rawClass=null}set klass(e){this._removeClasses(this._initialClasses),this._initialClasses="string"==typeof e?e.split(/\s+/):[],this._applyClasses(this._initialClasses),this._applyClasses(this._rawClass)}set ngClass(e){this._removeClasses(this._rawClass),this._applyClasses(this._initialClasses),this._iterableDiffer=null,this._keyValueDiffer=null,this._rawClass="string"==typeof e?e.split(/\s+/):e,this._rawClass&&(Object(i.ob)(this._rawClass)?this._iterableDiffer=this._iterableDiffers.find(this._rawClass).create():this._keyValueDiffer=this._keyValueDiffers.find(this._rawClass).create())}ngDoCheck(){if(this._iterableDiffer){const e=this._iterableDiffer.diff(this._rawClass);e&&this._applyIterableChanges(e)}else if(this._keyValueDiffer){const e=this._keyValueDiffer.diff(this._rawClass);e&&this._applyKeyValueChanges(e)}}_applyKeyValueChanges(e){e.forEachAddedItem(e=>this._toggleClass(e.key,e.currentValue)),e.forEachChangedItem(e=>this._toggleClass(e.key,e.currentValue)),e.forEachRemovedItem(e=>{e.previousValue&&this._toggleClass(e.key,!1)})}_applyIterableChanges(e){e.forEachAddedItem(e=>{if("string"!=typeof e.item)throw new Error("NgClass can only toggle CSS classes expressed as strings, got "+Object(i.tb)(e.item));this._toggleClass(e.item,!0)}),e.forEachRemovedItem(e=>this._toggleClass(e.item,!1))}_applyClasses(e){e&&(Array.isArray(e)||e instanceof Set?e.forEach(e=>this._toggleClass(e,!0)):Object.keys(e).forEach(t=>this._toggleClass(t,!!e[t])))}_removeClasses(e){e&&(Array.isArray(e)||e instanceof Set?e.forEach(e=>this._toggleClass(e,!1)):Object.keys(e).forEach(e=>this._toggleClass(e,!1)))}_toggleClass(e,t){(e=e.trim())&&e.split(/\s+/g).forEach(e=>{t?this._renderer.addClass(this._ngEl.nativeElement,e):this._renderer.removeClass(this._ngEl.nativeElement,e)})}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.t),i.Mb(i.u),i.Mb(i.m),i.Mb(i.E))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngClass",""]],inputs:{klass:["class","klass"],ngClass:"ngClass"}}),e})();class be{constructor(e,t,n,i){this.$implicit=e,this.ngForOf=t,this.index=n,this.count=i}get first(){return 0===this.index}get last(){return this.index===this.count-1}get even(){return this.index%2==0}get odd(){return!this.even}}let ge=(()=>{class e{constructor(e,t,n){this._viewContainer=e,this._template=t,this._differs=n,this._ngForOf=null,this._ngForOfDirty=!0,this._differ=null}set ngForOf(e){this._ngForOf=e,this._ngForOfDirty=!0}set ngForTrackBy(e){Object(i.U)()&&null!=e&&"function"!=typeof e&&console&&console.warn&&console.warn(`trackBy must be a function, but received ${JSON.stringify(e)}. See https://angular.io/api/common/NgForOf#change-propagation for more information.`),this._trackByFn=e}get ngForTrackBy(){return this._trackByFn}set ngForTemplate(e){e&&(this._template=e)}ngDoCheck(){if(this._ngForOfDirty){this._ngForOfDirty=!1;const n=this._ngForOf;if(!this._differ&&n)try{this._differ=this._differs.find(n).create(this.ngForTrackBy)}catch(t){throw new Error(`Cannot find a differ supporting object '${n}' of type '${e=n,e.name||typeof e}'. NgFor only supports binding to Iterables such as Arrays.`)}}var e;if(this._differ){const e=this._differ.diff(this._ngForOf);e&&this._applyChanges(e)}}_applyChanges(e){const t=[];e.forEachOperation((e,n,i)=>{if(null==e.previousIndex){const n=this._viewContainer.createEmbeddedView(this._template,new be(null,this._ngForOf,-1,-1),null===i?void 0:i),r=new _e(e,n);t.push(r)}else if(null==i)this._viewContainer.remove(null===n?void 0:n);else if(null!==n){const r=this._viewContainer.get(n);this._viewContainer.move(r,i);const s=new _e(e,r);t.push(s)}});for(let n=0;n{this._viewContainer.get(e.currentIndex).context.$implicit=e.item})}_perViewChange(e,t){e.context.$implicit=t.item}static ngTemplateContextGuard(e,t){return!0}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.P),i.Mb(i.L),i.Mb(i.t))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngFor","","ngForOf",""]],inputs:{ngForOf:"ngForOf",ngForTrackBy:"ngForTrackBy",ngForTemplate:"ngForTemplate"}}),e})();class _e{constructor(e,t){this.record=e,this.view=t}}let ye=(()=>{class e{constructor(e,t){this._viewContainer=e,this._context=new ve,this._thenTemplateRef=null,this._elseTemplateRef=null,this._thenViewRef=null,this._elseViewRef=null,this._thenTemplateRef=t}set ngIf(e){this._context.$implicit=this._context.ngIf=e,this._updateView()}set ngIfThen(e){we("ngIfThen",e),this._thenTemplateRef=e,this._thenViewRef=null,this._updateView()}set ngIfElse(e){we("ngIfElse",e),this._elseTemplateRef=e,this._elseViewRef=null,this._updateView()}_updateView(){this._context.$implicit?this._thenViewRef||(this._viewContainer.clear(),this._elseViewRef=null,this._thenTemplateRef&&(this._thenViewRef=this._viewContainer.createEmbeddedView(this._thenTemplateRef,this._context))):this._elseViewRef||(this._viewContainer.clear(),this._thenViewRef=null,this._elseTemplateRef&&(this._elseViewRef=this._viewContainer.createEmbeddedView(this._elseTemplateRef,this._context)))}static ngTemplateContextGuard(e,t){return!0}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.P),i.Mb(i.L))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngIf",""]],inputs:{ngIf:"ngIf",ngIfThen:"ngIfThen",ngIfElse:"ngIfElse"}}),e})();class ve{constructor(){this.$implicit=null,this.ngIf=null}}function we(e,t){if(t&&!t.createEmbeddedView)throw new Error(`${e} must be a TemplateRef, but received '${Object(i.tb)(t)}'.`)}class Se{constructor(e,t){this._viewContainerRef=e,this._templateRef=t,this._created=!1}create(){this._created=!0,this._viewContainerRef.createEmbeddedView(this._templateRef)}destroy(){this._created=!1,this._viewContainerRef.clear()}enforceState(e){e&&!this._created?this.create():!e&&this._created&&this.destroy()}}let Me=(()=>{class e{constructor(){this._defaultUsed=!1,this._caseCount=0,this._lastCaseCheckIndex=0,this._lastCasesMatched=!1}set ngSwitch(e){this._ngSwitch=e,0===this._caseCount&&this._updateDefaultCases(!0)}_addCase(){return this._caseCount++}_addDefault(e){this._defaultViews||(this._defaultViews=[]),this._defaultViews.push(e)}_matchCase(e){const t=e==this._ngSwitch;return this._lastCasesMatched=this._lastCasesMatched||t,this._lastCaseCheckIndex++,this._lastCaseCheckIndex===this._caseCount&&(this._updateDefaultCases(!this._lastCasesMatched),this._lastCaseCheckIndex=0,this._lastCasesMatched=!1),t}_updateDefaultCases(e){if(this._defaultViews&&e!==this._defaultUsed){this._defaultUsed=e;for(let t=0;t{class e{constructor(e,t,n){this.ngSwitch=n,n._addCase(),this._view=new Se(e,t)}ngDoCheck(){this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase))}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.P),i.Mb(i.L),i.Mb(Me,1))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngSwitchCase",""]],inputs:{ngSwitchCase:"ngSwitchCase"}}),e})(),ke=(()=>{class e{constructor(e,t,n){n._addDefault(new Se(e,t))}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.P),i.Mb(i.L),i.Mb(Me,1))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngSwitchDefault",""]]}),e})(),De=(()=>{class e{constructor(e,t,n){this._ngEl=e,this._differs=t,this._renderer=n,this._ngStyle=null,this._differ=null}set ngStyle(e){this._ngStyle=e,!this._differ&&e&&(this._differ=this._differs.find(e).create())}ngDoCheck(){if(this._differ){const e=this._differ.diff(this._ngStyle);e&&this._applyChanges(e)}}_setStyle(e,t){const[n,i]=e.split(".");null!=(t=null!=t&&i?`${t}${i}`:t)?this._renderer.setStyle(this._ngEl.nativeElement,n,t):this._renderer.removeStyle(this._ngEl.nativeElement,n)}_applyChanges(e){e.forEachRemovedItem(e=>this._setStyle(e.key,null)),e.forEachAddedItem(e=>this._setStyle(e.key,e.currentValue)),e.forEachChangedItem(e=>this._setStyle(e.key,e.currentValue))}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.m),i.Mb(i.u),i.Mb(i.E))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngStyle",""]],inputs:{ngStyle:"ngStyle"}}),e})(),Te=(()=>{class e{constructor(e){this._viewContainerRef=e,this._viewRef=null,this.ngTemplateOutletContext=null,this.ngTemplateOutlet=null}ngOnChanges(e){if(this._shouldRecreateView(e)){const e=this._viewContainerRef;this._viewRef&&e.remove(e.indexOf(this._viewRef)),this._viewRef=this.ngTemplateOutlet?e.createEmbeddedView(this.ngTemplateOutlet,this.ngTemplateOutletContext):null}else this._viewRef&&this.ngTemplateOutletContext&&this._updateExistingContext(this.ngTemplateOutletContext)}_shouldRecreateView(e){const t=e.ngTemplateOutletContext;return!!e.ngTemplateOutlet||t&&this._hasContextShapeChanged(t)}_hasContextShapeChanged(e){const t=Object.keys(e.previousValue||{}),n=Object.keys(e.currentValue||{});if(t.length===n.length){for(let e of n)if(-1===t.indexOf(e))return!0;return!1}return!0}_updateExistingContext(e){for(let t of Object.keys(e))this._viewRef.context[t]=this.ngTemplateOutletContext[t]}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.P))},e.\u0275dir=i.Hb({type:e,selectors:[["","ngTemplateOutlet",""]],inputs:{ngTemplateOutletContext:"ngTemplateOutletContext",ngTemplateOutlet:"ngTemplateOutlet"},features:[i.wb]}),e})();function Ce(e,t){return Error(`InvalidPipeArgument: '${t}' for pipe '${Object(i.tb)(e)}'`)}class Oe{createSubscription(e,t){return e.subscribe({next:t,error:e=>{throw e}})}dispose(e){e.unsubscribe()}onDestroy(e){e.unsubscribe()}}class Le{createSubscription(e,t){return e.then(t,e=>{throw e})}dispose(e){}onDestroy(e){}}const Re=new Le,Ee=new Oe;let Ae=(()=>{class e{constructor(e){this._ref=e,this._latestValue=null,this._subscription=null,this._obj=null,this._strategy=null}ngOnDestroy(){this._subscription&&this._dispose()}transform(e){return this._obj?e!==this._obj?(this._dispose(),this.transform(e)):this._latestValue:(e&&this._subscribe(e),this._latestValue)}_subscribe(e){this._obj=e,this._strategy=this._selectStrategy(e),this._subscription=this._strategy.createSubscription(e,t=>this._updateLatestValue(e,t))}_selectStrategy(t){if(Object(i.qb)(t))return Re;if(Object(i.pb)(t))return Ee;throw Ce(e,t)}_dispose(){this._strategy.dispose(this._subscription),this._latestValue=null,this._subscription=null,this._obj=null}_updateLatestValue(e,t){e===this._obj&&(this._latestValue=t,this._ref.markForCheck())}}return e.\u0275fac=function(t){return new(t||e)(i.fc())},e.\u0275pipe=i.Lb({name:"async",type:e,pure:!1}),e})(),Ie=(()=>{class e{transform(t){if(!t)return t;if("string"!=typeof t)throw Ce(e,t);return t.toLowerCase()}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"lowercase",type:e,pure:!0}),e})();const Pe=/(?:[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08BD\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312E\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FEA\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AE\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE83\uDE86-\uDE89\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F\uDFE0\uDFE1]|\uD821[\uDC00-\uDFEC]|\uD822[\uDC00-\uDEF2]|\uD82C[\uDC00-\uDD1E\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D])\S*/g;let je=(()=>{class e{transform(t){if(!t)return t;if("string"!=typeof t)throw Ce(e,t);return t.replace(Pe,e=>e[0].toUpperCase()+e.substr(1).toLowerCase())}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"titlecase",type:e,pure:!0}),e})(),Ne=(()=>{class e{transform(t){if(!t)return t;if("string"!=typeof t)throw Ce(e,t);return t.toUpperCase()}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"uppercase",type:e,pure:!0}),e})(),Fe=(()=>{class e{constructor(e){this.locale=e}transform(t,n="mediumDate",i,r){if(null==t||""===t||t!=t)return null;try{return Q(t,n,r||this.locale,i)}catch(s){throw Ce(e,s.message)}}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.v))},e.\u0275pipe=i.Lb({name:"date",type:e,pure:!0}),e})();const Ye=/#/g;let ze=(()=>{class e{constructor(e){this._localization=e}transform(t,n,i){if(null==t)return"";if("object"!=typeof n||null===n)throw Ce(e,n);return n[function(e,t,n,i){let r="="+e;if(t.indexOf(r)>-1)return r;if(r=n.getPluralCategory(e,i),t.indexOf(r)>-1)return r;if(t.indexOf("other")>-1)return"other";throw new Error(`No plural message found for value "${e}"`)}(t,Object.keys(n),this._localization,i)].replace(Ye,t.toString())}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(he))},e.\u0275pipe=i.Lb({name:"i18nPlural",type:e,pure:!0}),e})(),$e=(()=>{class e{transform(e){return JSON.stringify(e,null,2)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"json",type:e,pure:!1}),e})(),He=(()=>{class e{constructor(e){this.differs=e,this.keyValues=[]}transform(e,t=We){if(!e||!(e instanceof Map)&&"object"!=typeof e)return null;this.differ||(this.differ=this.differs.find(e).create());const n=this.differ.diff(e);return n&&(this.keyValues=[],n.forEachItem(e=>{this.keyValues.push({key:e.key,value:e.currentValue})}),this.keyValues.sort(t)),this.keyValues}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.u))},e.\u0275pipe=i.Lb({name:"keyvalue",type:e,pure:!1}),e})();function We(e,t){const n=e.key,i=t.key;if(n===i)return 0;if(void 0===n)return 1;if(void 0===i)return-1;if(null===n)return 1;if(null===i)return-1;if("string"==typeof n&&"string"==typeof i)return n{class e{constructor(e){this._locale=e}transform(t,n,i){if(Ue(t))return null;i=i||this._locale;try{return function(e,t,n){return le(e,ue(Y(t,D.Decimal),F(t,R.MinusSign)),t,R.Group,R.Decimal,n)}(qe(t),i,n)}catch(r){throw Ce(e,r.message)}}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.v))},e.\u0275pipe=i.Lb({name:"number",type:e,pure:!0}),e})(),Be=(()=>{class e{constructor(e){this._locale=e}transform(t,n,i){if(Ue(t))return null;i=i||this._locale;try{return function(e,t,n){return le(e,ue(Y(t,D.Percent),F(t,R.MinusSign)),t,R.Group,R.Decimal,n,!0).replace(new RegExp("%","g"),F(t,R.PercentSign))}(qe(t),i,n)}catch(r){throw Ce(e,r.message)}}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(i.v))},e.\u0275pipe=i.Lb({name:"percent",type:e,pure:!0}),e})();function Ue(e){return null==e||""===e||e!=e}function qe(e){if("string"==typeof e&&!isNaN(Number(e)-parseFloat(e)))return Number(e);if("number"!=typeof e)throw new Error(e+" is not a number");return e}let Ge=(()=>{class e{}return e.\u0275mod=i.Kb({type:e}),e.\u0275inj=i.Jb({factory:function(t){return new(t||e)},providers:[{provide:he,useClass:fe}]}),e})();const Je="browser";function Qe(e){return e===Je}let Ke=(()=>{class e{}return e.\u0275prov=Object(i.Ib)({token:e,providedIn:"root",factory:()=>new Ze(Object(i.dc)(c),window,Object(i.dc)(i.n))}),e})();class Ze{constructor(e,t,n){this.document=e,this.window=t,this.errorHandler=n,this.offset=()=>[0,0]}setOffset(e){this.offset=Array.isArray(e)?()=>e:e}getScrollPosition(){return this.supportsScrolling()?[this.window.scrollX,this.window.scrollY]:[0,0]}scrollToPosition(e){this.supportsScrolling()&&this.window.scrollTo(e[0],e[1])}scrollToAnchor(e){if(this.supportsScrolling()){const t=this.document.getElementById(e)||this.document.getElementsByName(e)[0];t&&this.scrollToElement(t)}}setHistoryScrollRestoration(e){if(this.supportScrollRestoration()){const t=this.window.history;t&&t.scrollRestoration&&(t.scrollRestoration=e)}}scrollToElement(e){const t=e.getBoundingClientRect(),n=t.left+this.window.pageXOffset,i=t.top+this.window.pageYOffset,r=this.offset();this.window.scrollTo(n-r[0],i-r[1])}supportScrollRestoration(){try{if(!this.window||!this.window.scrollTo)return!1;const e=Xe(this.window.history)||Xe(Object.getPrototypeOf(this.window.history));return!(!e||!e.writable&&!e.set)}catch(e){return!1}}supportsScrolling(){try{return!!this.window.scrollTo}catch(e){return!1}}}function Xe(e){return Object.getOwnPropertyDescriptor(e,"scrollRestoration")}},SatO:function(e,t,n){!function(e){"use strict";e.defineLocale("zh-hk",{months:"\u4e00\u6708_\u4e8c\u6708_\u4e09\u6708_\u56db\u6708_\u4e94\u6708_\u516d\u6708_\u4e03\u6708_\u516b\u6708_\u4e5d\u6708_\u5341\u6708_\u5341\u4e00\u6708_\u5341\u4e8c\u6708".split("_"),monthsShort:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),weekdays:"\u661f\u671f\u65e5_\u661f\u671f\u4e00_\u661f\u671f\u4e8c_\u661f\u671f\u4e09_\u661f\u671f\u56db_\u661f\u671f\u4e94_\u661f\u671f\u516d".split("_"),weekdaysShort:"\u9031\u65e5_\u9031\u4e00_\u9031\u4e8c_\u9031\u4e09_\u9031\u56db_\u9031\u4e94_\u9031\u516d".split("_"),weekdaysMin:"\u65e5_\u4e00_\u4e8c_\u4e09_\u56db_\u4e94_\u516d".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY\u5e74M\u6708D\u65e5",LLL:"YYYY\u5e74M\u6708D\u65e5 HH:mm",LLLL:"YYYY\u5e74M\u6708D\u65e5dddd HH:mm",l:"YYYY/M/D",ll:"YYYY\u5e74M\u6708D\u65e5",lll:"YYYY\u5e74M\u6708D\u65e5 HH:mm",llll:"YYYY\u5e74M\u6708D\u65e5dddd HH:mm"},meridiemParse:/\u51cc\u6668|\u65e9\u4e0a|\u4e0a\u5348|\u4e2d\u5348|\u4e0b\u5348|\u665a\u4e0a/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u51cc\u6668"===t||"\u65e9\u4e0a"===t||"\u4e0a\u5348"===t?e:"\u4e2d\u5348"===t?e>=11?e:e+12:"\u4e0b\u5348"===t||"\u665a\u4e0a"===t?e+12:void 0},meridiem:function(e,t,n){var i=100*e+t;return i<600?"\u51cc\u6668":i<900?"\u65e9\u4e0a":i<1200?"\u4e0a\u5348":1200===i?"\u4e2d\u5348":i<1800?"\u4e0b\u5348":"\u665a\u4e0a"},calendar:{sameDay:"[\u4eca\u5929]LT",nextDay:"[\u660e\u5929]LT",nextWeek:"[\u4e0b]ddddLT",lastDay:"[\u6628\u5929]LT",lastWeek:"[\u4e0a]ddddLT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(\u65e5|\u6708|\u9031)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"\u65e5";case"M":return e+"\u6708";case"w":case"W":return e+"\u9031";default:return e}},relativeTime:{future:"%s\u5f8c",past:"%s\u524d",s:"\u5e7e\u79d2",ss:"%d \u79d2",m:"1 \u5206\u9418",mm:"%d \u5206\u9418",h:"1 \u5c0f\u6642",hh:"%d \u5c0f\u6642",d:"1 \u5929",dd:"%d \u5929",M:"1 \u500b\u6708",MM:"%d \u500b\u6708",y:"1 \u5e74",yy:"%d \u5e74"}})}(n("wd/R"))},SeVD:function(e,t,n){"use strict";n.d(t,"a",(function(){return u}));var i=n("ngJS"),r=n("NJ4a"),s=n("Lhse"),o=n("kJWO"),a=n("I55L"),c=n("c2HN"),l=n("XoHu");const u=e=>{if(e&&"function"==typeof e[o.a])return u=e,e=>{const t=u[o.a]();if("function"!=typeof t.subscribe)throw new TypeError("Provided object does not correctly implement Symbol.observable");return t.subscribe(e)};if(Object(a.a)(e))return Object(i.a)(e);if(Object(c.a)(e))return n=e,e=>(n.then(t=>{e.closed||(e.next(t),e.complete())},t=>e.error(t)).then(null,r.a),e);if(e&&"function"==typeof e[s.a])return t=e,e=>{const n=t[s.a]();for(;;){let t;try{t=n.next()}catch(i){return e.error(i),e}if(t.done){e.complete();break}if(e.next(t.value),e.closed)break}return"function"==typeof n.return&&e.add(()=>{n.return&&n.return()}),e};{const t=Object(l.a)(e)?"an invalid object":`'${e}'`;throw new TypeError(`You provided ${t} where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.`)}var t,n,u}},SpAZ:function(e,t,n){"use strict";function i(e){return e}n.d(t,"a",(function(){return i}))},SxV6:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("sVev"),r=n("pLZG"),s=n("IzEk"),o=n("xbPD"),a=n("XDbj"),c=n("SpAZ");function l(e,t){const n=arguments.length>=2;return l=>l.pipe(e?Object(r.a)((t,n)=>e(t,n,l)):c.a,Object(s.a)(1),n?Object(o.a)(t):Object(a.a)(()=>new i.a))}},TFwu:function(e,t,n){"use strict";var i=n("25cm"),r=n("jN84"),s=n("mkut");t.a=function(e){return Object(i.a)(e,s.a,r.a)}},TJUb:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");let o=(()=>{class e{transform(e,t){return r.a.isPlainObject(t)?r.a.get(t,e,e):e}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=s.Lb({name:"map",type:e,pure:!0}),e})()},TKcr:function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));class i{propertyValue(e){return getComputedStyle(document.body).getPropertyValue("--"+e)}}},TWQb:function(e,t,n){var i=n("/GqU"),r=n("UMSQ"),s=n("I8vh"),o=function(e){return function(t,n,o){var a,c=i(t),l=r(c.length),u=s(o,l);if(e&&n!=n){for(;l>u;)if((a=c[u++])!=a)return!0}else for(;l>u;u++)if((e||u in c)&&c[u]===n)return e||u||0;return!e&&-1}};e.exports={includes:o(!0),indexOf:o(!1)}},TYzs:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){const t=parseInt(e,10);return isNaN(t)?e:e+(1===Math.floor(t/10)?"th":t%10==1?"st":t%10==2?"nd":t%10==3?"rd":"th")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"ordinal",type:e,pure:!0}),e})()},TeQF:function(e,t,n){"use strict";var i=n("I+eb"),r=n("tycR").filter;i({target:"Array",proto:!0,forced:!n("Hd5f")("filter")},{filter:function(e){return r(this,e,arguments.length>1?arguments[1]:void 0)}})},TnHx:function(e,t,n){"use strict";var i=n("25cm"),r=n("n561"),s=n("4/q3");t.a=function(e){return Object(i.a)(e,s.a,r.a)}},U6JX:function(e,t,n){"use strict";t.a=function(e,t){return function(n){return e(t(n))}}},UDhR:function(e,t,n){!function(e){"use strict";e.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(e,t){return 12===e&&(e=0),"pagi"===t?e:"siang"===t?e>=11?e:e+12:"sore"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"pagi":e<15?"siang":e<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",ss:"%d detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:0,doy:6}})}(n("wd/R"))},UMSQ:function(e,t,n){var i=n("ppGB"),r=Math.min;e.exports=function(e){return e>0?r(i(e),9007199254740991):0}},USCx:function(e,t,n){!function(e){"use strict";e.defineLocale("ga",{months:["Ean\xe1ir","Feabhra","M\xe1rta","Aibre\xe1n","Bealtaine","Meitheamh","I\xfail","L\xfanasa","Me\xe1n F\xf3mhair","Deireadh F\xf3mhair","Samhain","Nollaig"],monthsShort:["Ean","Feabh","M\xe1rt","Aib","Beal","Meith","I\xfail","L\xfan","M.F.","D.F.","Samh","Noll"],monthsParseExact:!0,weekdays:["D\xe9 Domhnaigh","D\xe9 Luain","D\xe9 M\xe1irt","D\xe9 C\xe9adaoin","D\xe9ardaoin","D\xe9 hAoine","D\xe9 Sathairn"],weekdaysShort:["Domh","Luan","M\xe1irt","C\xe9ad","D\xe9ar","Aoine","Sath"],weekdaysMin:["Do","Lu","M\xe1","C\xe9","D\xe9","A","Sa"],longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Inniu ag] LT",nextDay:"[Am\xe1rach ag] LT",nextWeek:"dddd [ag] LT",lastDay:"[Inn\xe9 ag] LT",lastWeek:"dddd [seo caite] [ag] LT",sameElse:"L"},relativeTime:{future:"i %s",past:"%s \xf3 shin",s:"c\xfapla soicind",ss:"%d soicind",m:"n\xf3im\xe9ad",mm:"%d n\xf3im\xe9ad",h:"uair an chloig",hh:"%d uair an chloig",d:"l\xe1",dd:"%d l\xe1",M:"m\xed",MM:"%d m\xedonna",y:"bliain",yy:"%d bliain"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(n("wd/R"))},UTVS:function(e,t,n){var i=n("ewvW"),r={}.hasOwnProperty;e.exports=function(e,t){return r.call(i(e),t)}},UpQW:function(e,t,n){!function(e){"use strict";var t=["\u062c\u0646\u0648\u0631\u06cc","\u0641\u0631\u0648\u0631\u06cc","\u0645\u0627\u0631\u0686","\u0627\u067e\u0631\u06cc\u0644","\u0645\u0626\u06cc","\u062c\u0648\u0646","\u062c\u0648\u0644\u0627\u0626\u06cc","\u0627\u06af\u0633\u062a","\u0633\u062a\u0645\u0628\u0631","\u0627\u06a9\u062a\u0648\u0628\u0631","\u0646\u0648\u0645\u0628\u0631","\u062f\u0633\u0645\u0628\u0631"],n=["\u0627\u062a\u0648\u0627\u0631","\u067e\u06cc\u0631","\u0645\u0646\u06af\u0644","\u0628\u062f\u06be","\u062c\u0645\u0639\u0631\u0627\u062a","\u062c\u0645\u0639\u06c1","\u06c1\u0641\u062a\u06c1"];e.defineLocale("ur",{months:t,monthsShort:t,weekdays:n,weekdaysShort:n,weekdaysMin:n,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd\u060c D MMMM YYYY HH:mm"},meridiemParse:/\u0635\u0628\u062d|\u0634\u0627\u0645/,isPM:function(e){return"\u0634\u0627\u0645"===e},meridiem:function(e,t,n){return e<12?"\u0635\u0628\u062d":"\u0634\u0627\u0645"},calendar:{sameDay:"[\u0622\u062c \u0628\u0648\u0642\u062a] LT",nextDay:"[\u06a9\u0644 \u0628\u0648\u0642\u062a] LT",nextWeek:"dddd [\u0628\u0648\u0642\u062a] LT",lastDay:"[\u06af\u0630\u0634\u062a\u06c1 \u0631\u0648\u0632 \u0628\u0648\u0642\u062a] LT",lastWeek:"[\u06af\u0630\u0634\u062a\u06c1] dddd [\u0628\u0648\u0642\u062a] LT",sameElse:"L"},relativeTime:{future:"%s \u0628\u0639\u062f",past:"%s \u0642\u0628\u0644",s:"\u0686\u0646\u062f \u0633\u06cc\u06a9\u0646\u0688",ss:"%d \u0633\u06cc\u06a9\u0646\u0688",m:"\u0627\u06cc\u06a9 \u0645\u0646\u0679",mm:"%d \u0645\u0646\u0679",h:"\u0627\u06cc\u06a9 \u06af\u06be\u0646\u0679\u06c1",hh:"%d \u06af\u06be\u0646\u0679\u06d2",d:"\u0627\u06cc\u06a9 \u062f\u0646",dd:"%d \u062f\u0646",M:"\u0627\u06cc\u06a9 \u0645\u0627\u06c1",MM:"%d \u0645\u0627\u06c1",y:"\u0627\u06cc\u06a9 \u0633\u0627\u0644",yy:"%d \u0633\u0627\u0644"},preparse:function(e){return e.replace(/\u060c/g,",")},postformat:function(e){return e.replace(/,/g,"\u060c")},week:{dow:1,doy:4}})}(n("wd/R"))},Ur1D:function(e,t,n){!function(e){"use strict";e.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",ss:"%d mzuzwana",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(e,t,n){return e<11?"ekuseni":e<15?"emini":e<19?"entsambama":"ebusuku"},meridiemHour:function(e,t){return 12===e&&(e=0),"ekuseni"===t?e:"emini"===t?e>=11?e:e+12:"entsambama"===t||"ebusuku"===t?0===e?0:e+12:void 0},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,doy:4}})}(n("wd/R"))},UudT:function(e,t,n){"use strict";var i=n("U6JX"),r=Object(i.a)(Object.getPrototypeOf,Object);t.a=r},UxlC:function(e,t,n){"use strict";var i=n("14Sl"),r=n("glrk"),s=n("UMSQ"),o=n("ppGB"),a=n("HYAF"),c=n("iqWW"),l=n("DLK6"),u=n("FMNM"),d=Math.max,h=Math.min;i("replace",2,(function(e,t,n,i){var f=i.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,p=i.REPLACE_KEEPS_$0,m=f?"$":"$0";return[function(n,i){var r=a(this),s=null==n?void 0:n[e];return void 0!==s?s.call(n,r,i):t.call(String(r),n,i)},function(e,i){if(!f&&p||"string"==typeof i&&-1===i.indexOf(m)){var a=n(t,e,this,i);if(a.done)return a.value}var b=r(e),g=String(this),_="function"==typeof i;_||(i=String(i));var y=b.global;if(y){var v=b.unicode;b.lastIndex=0}for(var w=[];;){var S=u(b,g);if(null===S)break;if(w.push(S),!y)break;""===String(S[0])&&(b.lastIndex=c(g,s(b.lastIndex),v))}for(var M,x="",k=0,D=0;D=k&&(x+=g.slice(k,C)+A,k=C+T.length)}return x+g.slice(k)}]}))},"V/fk":function(e,t,n){"use strict";n.d(t,"a",(function(){return f}));var i=n("SVse"),r=n("s7LF"),s=n("iInd"),o=n("G0yt"),a=n("Hicy"),c=n("hrfs"),l=n("WF9J"),u=n("yGOH"),d=n("9Xeq"),h=n("8Y7J");let f=(()=>{class e{}return e.\u0275mod=h.Kb({type:e}),e.\u0275inj=h.Jb({factory:function(t){return new(t||e)},providers:[],imports:[[i.c,r.m,r.x,o.c,o.y,o.A,o.F,c.b,r.x,d.a,u.a,o.l,a.b,l.b,s.i,o.h,o.C]]}),e})()},V2x9:function(e,t,n){!function(e){"use strict";e.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Ju\xf1u_Jullu_Agustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sesta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sest_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Ses_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"segundu balun",ss:"segundu %d",m:"minutu ida",mm:"minutu %d",h:"oras ida",hh:"oras %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(n("wd/R"))},VRyK:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("HDdC"),r=n("z+Ro"),s=n("bHdf"),o=n("yCtX");function a(...e){let t=Number.POSITIVE_INFINITY,n=null,a=e[e.length-1];return Object(r.a)(a)?(n=e.pop(),e.length>1&&"number"==typeof e[e.length-1]&&(t=e.pop())):"number"==typeof a&&(t=e.pop()),null===n&&1===e.length&&e[0]instanceof i.a?e[0]:Object(s.a)(t)(Object(o.a)(e,n))}},VTlA:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("mSOc"),r=n("ufoC"),s=n("8Y7J");let o=(()=>{class e{constructor(e,t){this.taskMessageService=e,this.summaryService=t}init(e,t,n,i,r,s,o){this.getUpdate=e,this.preProcessing=t,this.setList=n,this.onFetchError=i,this.taskFilter=r,this.itemFilter=s,this.builders=o||{},this.summaryDataSubscription=this.summaryService.subscribe(e=>{this.summary=e,this.fetch()},this.onFetchError)}fetch(){this.getUpdate().subscribe(e=>{this.updateData(e,this.summary.executing_tasks.filter(this.taskFilter))},this.onFetchError)}updateData(e,t){const n=this.preProcessing?this.preProcessing(e):e;this.addMissing(n,t),n.forEach(e=>{const n=t.filter(t=>this.itemFilter(e,t));e.cdExecuting=this.getTaskAction(n)}),this.setList(n)}addMissing(e,t){const n=this.builders.default;t.forEach(t=>{const i=e.find(e=>this.itemFilter(e,t)),r=this.builders[t.name];i||!r&&!n||e.push(r?r(t.metadata):n(t.metadata))})}getTaskAction(e){if(0!==e.length)return e.map(e=>{const t=e.progress?` ${e.progress}%`:"";return this.taskMessageService.getRunningText(e)+"..."+t}).join(", ")}ngOnDestroy(){this.summaryDataSubscription&&this.summaryDataSubscription.unsubscribe()}}return e.\u0275fac=function(t){return new(t||e)(s.dc(r.a),s.dc(i.a))},e.\u0275prov=s.Ib({token:e,factory:e.\u0275fac}),e})()},VXsX:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");class o{constructor(e,t,n){this.name=e,this.metadata=t,this.onTaskFinished=n}}let a=(()=>{class e{constructor(){this.subscriptions=[]}init(e){return e.subscribe(e=>{const t=e.executing_tasks,n=e.finished_tasks,i=[];for(const r of this.subscriptions){const e=this._getTask(r,n),s=this._getTask(r,t);null!==e&&null===s&&r.onTaskFinished(e),null!==s&&i.push(r),this.subscriptions=i}})}subscribe(e,t,n){this.subscriptions.push(new o(e,t,n))}_getTask(e,t){for(const n of t)if(n.name===e.name&&r.a.isEqual(n.metadata,e.metadata))return n;return null}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=s.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},Vclq:function(e,t,n){!function(e){"use strict";var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),n="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),i=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],r=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-us",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,i){return e?/-MMM-/.test(i)?n[e.month()]:t[e.month()]:t},monthsRegex:r,monthsShortRegex:r,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:i,longMonthsParse:i,shortMonthsParse:i,weekdays:"domingo_lunes_martes_mi\xe9rcoles_jueves_viernes_s\xe1bado".split("_"),weekdaysShort:"dom._lun._mar._mi\xe9._jue._vie._s\xe1b.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_s\xe1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"MM/DD/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[ma\xf1ana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un d\xeda",dd:"%d d\xedas",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un a\xf1o",yy:"%d a\xf1os"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:0,doy:6}})}(n("wd/R"))},Vhfg:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("lJxs"),r=n("WE5d"),s=n("ej+x"),o=n("8Y7J");let a=(()=>{class e{constructor(e){this.featureToggles=e}canActivate(e){return this.featureToggles.get().pipe(Object(i.a)(t=>{if(!1===t[e.routeConfig.path])throw new r.b;return!0}))}canActivateChild(e){return this.canActivate(e.parent)}}return e.\u0275fac=function(t){return new(t||e)(o.dc(s.a))},e.\u0275prov=o.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},VpIT:function(e,t,n){var i=n("xDBR"),r=n("xs3f");(e.exports=function(e,t){return r[e]||(r[e]=void 0!==t?t:{})})("versions",[]).push({version:"3.12.1",mode:i?"pure":"global",copyright:"\xa9 2021 Denis Pushkarev (zloirock.ru)"})},Vu81:function(e,t,n){var i=n("0GbY"),r=n("JBy8"),s=n("dBg+"),o=n("glrk");e.exports=i("Reflect","ownKeys")||function(e){var t=r.f(o(e)),n=s.f;return n?t.concat(n(e)):t}},VxPD:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("yJti"),r=n("e2NH");class s extends r.a{constructor(e=i.a.ValueOk,t=""){switch(super(),e){case i.a.ValueOk:this.type="light",this.msg="";break;case i.a.ValueNone:this.type="info",this.msg=(t?"Retrieving data for " + t + ".":"Retrieving data.")+" "+"Please wait...";break;case i.a.ValueStale:this.type="warning",this.msg=t?"Displaying previously cached data for " + t + ".":"Displaying previously cached data.";break;case i.a.ValueException:this.type="danger",this.msg=(t?"Could not load data for " + t + ".":"Could not load data.")+" "+"Please check the cluster health."}}}},WE5d:function(e,t,n){"use strict";n.d(t,"a",(function(){return r})),n.d(t,"b",(function(){return s})),n.d(t,"c",(function(){return o}));var i=n("oxzT");class r extends Error{}class s extends r{constructor(){super(...arguments),this.header="Page Not Found",this.message="Sorry, we couldn\u2019t find what you were looking for.\n The page you requested may have been changed or moved.",this.icon=i.a.warning}}class o extends r{constructor(){super(...arguments),this.header="User Denied",this.message="Sorry, the user does not exist in Ceph.\n You'll be logged out from the Identity Provider when you retry logging in.",this.icon=i.a.warning}}},WF9J:function(e,t,n){"use strict";n.d(t,"a",(function(){return z})),n.d(t,"b",(function(){return $})),n("TeQF"),n("QWBl"),n("4mDm"),n("zKZe"),n("07d7"),n("4l63"),n("PKPk"),n("ENF9"),n("3bBZ");var i=n("hKI/"),r=n.n(i),s=n("9/5/"),o=n.n(s),a=n("uyHG"),c=n.n(a),l=function(){if("undefined"!=typeof Map)return Map;function e(e,t){var n=-1;return e.some((function(e,i){return e[0]===t&&(n=i,!0)})),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(t){var n=e(this.__entries__,t),i=this.__entries__[n];return i&&i[1]},t.prototype.set=function(t,n){var i=e(this.__entries__,t);~i?this.__entries__[i][1]=n:this.__entries__.push([t,n])},t.prototype.delete=function(t){var n=this.__entries__,i=e(n,t);~i&&n.splice(i,1)},t.prototype.has=function(t){return!!~e(this.__entries__,t)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(e,t){void 0===t&&(t=null);for(var n=0,i=this.__entries__;n0},e.prototype.connect_=function(){u&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),p?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){u&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(e){var t=e.propertyName,n=void 0===t?"":t;f.some((function(e){return!!~n.indexOf(e)}))&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),b=function(e,t){for(var n=0,i=Object.keys(t);n0},e}(),D="undefined"!=typeof WeakMap?new WeakMap:new l,T=function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var n=m.getInstance(),i=new k(t,n,this);D.set(this,i)};["observe","unobserve","disconnect"].forEach((function(e){T.prototype[e]=function(){var t;return(t=D.get(this))[e].apply(t,arguments)}}));var C=void 0!==d.ResizeObserver?d.ResizeObserver:T,O=n("AxL3"),L=n.n(O);function R(e){return e&&e.ownerDocument&&e.ownerDocument.defaultView?e.ownerDocument.defaultView:window}function E(e){return e&&e.ownerDocument?e.ownerDocument:document}n("E9XD"),n("sMBO"),n("rB9j"),n("Rm1S"),n("UxlC");var A=null,I=null;function P(e){if(null===A){var t=E(e);if(void 0===t)return A=0;var n=t.body,i=t.createElement("div");i.classList.add("simplebar-hide-scrollbar"),n.appendChild(i);var r=i.getBoundingClientRect().right;n.removeChild(i),A=r}return A}L.a&&window.addEventListener("resize",(function(){I!==window.devicePixelRatio&&(I=window.devicePixelRatio,A=null)}));var j=function(){function e(t,n){var i=this;this.onScroll=function(){var e=R(i.el);i.scrollXTicking||(e.requestAnimationFrame(i.scrollX),i.scrollXTicking=!0),i.scrollYTicking||(e.requestAnimationFrame(i.scrollY),i.scrollYTicking=!0)},this.scrollX=function(){i.axis.x.isOverflowing&&(i.showScrollbar("x"),i.positionScrollbar("x")),i.scrollXTicking=!1},this.scrollY=function(){i.axis.y.isOverflowing&&(i.showScrollbar("y"),i.positionScrollbar("y")),i.scrollYTicking=!1},this.onMouseEnter=function(){i.showScrollbar("x"),i.showScrollbar("y")},this.onMouseMove=function(e){i.mouseX=e.clientX,i.mouseY=e.clientY,(i.axis.x.isOverflowing||i.axis.x.forceVisible)&&i.onMouseMoveForAxis("x"),(i.axis.y.isOverflowing||i.axis.y.forceVisible)&&i.onMouseMoveForAxis("y")},this.onMouseLeave=function(){i.onMouseMove.cancel(),(i.axis.x.isOverflowing||i.axis.x.forceVisible)&&i.onMouseLeaveForAxis("x"),(i.axis.y.isOverflowing||i.axis.y.forceVisible)&&i.onMouseLeaveForAxis("y"),i.mouseX=-1,i.mouseY=-1},this.onWindowResize=function(){i.scrollbarWidth=i.getScrollbarWidth(),i.hideNativeScrollbar()},this.hideScrollbars=function(){i.axis.x.track.rect=i.axis.x.track.el.getBoundingClientRect(),i.axis.y.track.rect=i.axis.y.track.el.getBoundingClientRect(),i.isWithinBounds(i.axis.y.track.rect)||(i.axis.y.scrollbar.el.classList.remove(i.classNames.visible),i.axis.y.isVisible=!1),i.isWithinBounds(i.axis.x.track.rect)||(i.axis.x.scrollbar.el.classList.remove(i.classNames.visible),i.axis.x.isVisible=!1)},this.onPointerEvent=function(e){var t,n;i.axis.x.track.rect=i.axis.x.track.el.getBoundingClientRect(),i.axis.y.track.rect=i.axis.y.track.el.getBoundingClientRect(),(i.axis.x.isOverflowing||i.axis.x.forceVisible)&&(t=i.isWithinBounds(i.axis.x.track.rect)),(i.axis.y.isOverflowing||i.axis.y.forceVisible)&&(n=i.isWithinBounds(i.axis.y.track.rect)),(t||n)&&(e.preventDefault(),e.stopPropagation(),"mousedown"===e.type&&(t&&(i.axis.x.scrollbar.rect=i.axis.x.scrollbar.el.getBoundingClientRect(),i.isWithinBounds(i.axis.x.scrollbar.rect)?i.onDragStart(e,"x"):i.onTrackClick(e,"x")),n&&(i.axis.y.scrollbar.rect=i.axis.y.scrollbar.el.getBoundingClientRect(),i.isWithinBounds(i.axis.y.scrollbar.rect)?i.onDragStart(e,"y"):i.onTrackClick(e,"y"))))},this.drag=function(t){var n=i.axis[i.draggedAxis].track,r=n.rect[i.axis[i.draggedAxis].sizeAttr],s=i.axis[i.draggedAxis].scrollbar,o=i.contentWrapperEl[i.axis[i.draggedAxis].scrollSizeAttr],a=parseInt(i.elStyles[i.axis[i.draggedAxis].sizeAttr],10);t.preventDefault(),t.stopPropagation();var c=(("y"===i.draggedAxis?t.pageY:t.pageX)-n.rect[i.axis[i.draggedAxis].offsetAttr]-i.axis[i.draggedAxis].dragOffset)/(r-s.size)*(o-a);"x"===i.draggedAxis&&(c=i.isRtl&&e.getRtlHelpers().isRtlScrollbarInverted?c-(r+s.size):c,c=i.isRtl&&e.getRtlHelpers().isRtlScrollingInverted?-c:c),i.contentWrapperEl[i.axis[i.draggedAxis].scrollOffsetAttr]=c},this.onEndDrag=function(e){var t=E(i.el),n=R(i.el);e.preventDefault(),e.stopPropagation(),i.el.classList.remove(i.classNames.dragging),t.removeEventListener("mousemove",i.drag,!0),t.removeEventListener("mouseup",i.onEndDrag,!0),i.removePreventClickId=n.setTimeout((function(){t.removeEventListener("click",i.preventClick,!0),t.removeEventListener("dblclick",i.preventClick,!0),i.removePreventClickId=null}))},this.preventClick=function(e){e.preventDefault(),e.stopPropagation()},this.el=t,this.minScrollbarWidth=20,this.options=Object.assign({},e.defaultOptions,{},n),this.classNames=Object.assign({},e.defaultOptions.classNames,{},this.options.classNames),this.axis={x:{scrollOffsetAttr:"scrollLeft",sizeAttr:"width",scrollSizeAttr:"scrollWidth",offsetSizeAttr:"offsetWidth",offsetAttr:"left",overflowAttr:"overflowX",dragOffset:0,isOverflowing:!0,isVisible:!1,forceVisible:!1,track:{},scrollbar:{}},y:{scrollOffsetAttr:"scrollTop",sizeAttr:"height",scrollSizeAttr:"scrollHeight",offsetSizeAttr:"offsetHeight",offsetAttr:"top",overflowAttr:"overflowY",dragOffset:0,isOverflowing:!0,isVisible:!1,forceVisible:!1,track:{},scrollbar:{}}},this.removePreventClickId=null,e.instances.has(this.el)||(this.recalculate=r()(this.recalculate.bind(this),64),this.onMouseMove=r()(this.onMouseMove.bind(this),64),this.hideScrollbars=o()(this.hideScrollbars.bind(this),this.options.timeout),this.onWindowResize=o()(this.onWindowResize.bind(this),64,{leading:!0}),e.getRtlHelpers=c()(e.getRtlHelpers),this.init())}e.getRtlHelpers=function(){var t=document.createElement("div");t.innerHTML='
';var n=t.firstElementChild;document.body.appendChild(n);var i=n.firstElementChild;n.scrollLeft=0;var r=e.getOffset(n),s=e.getOffset(i);n.scrollLeft=999;var o=e.getOffset(i);return{isRtlScrollingInverted:r.left!==s.left&&s.left-o.left!=0,isRtlScrollbarInverted:r.left!==s.left}},e.getOffset=function(e){var t=e.getBoundingClientRect(),n=E(e),i=R(e);return{top:t.top+(i.pageYOffset||n.documentElement.scrollTop),left:t.left+(i.pageXOffset||n.documentElement.scrollLeft)}};var t=e.prototype;return t.init=function(){e.instances.set(this.el,this),L.a&&(this.initDOM(),this.scrollbarWidth=this.getScrollbarWidth(),this.recalculate(),this.initListeners())},t.initDOM=function(){var e=this;if(Array.prototype.filter.call(this.el.children,(function(t){return t.classList.contains(e.classNames.wrapper)})).length)this.wrapperEl=this.el.querySelector("."+this.classNames.wrapper),this.contentWrapperEl=this.options.scrollableNode||this.el.querySelector("."+this.classNames.contentWrapper),this.contentEl=this.options.contentNode||this.el.querySelector("."+this.classNames.contentEl),this.offsetEl=this.el.querySelector("."+this.classNames.offset),this.maskEl=this.el.querySelector("."+this.classNames.mask),this.placeholderEl=this.findChild(this.wrapperEl,"."+this.classNames.placeholder),this.heightAutoObserverWrapperEl=this.el.querySelector("."+this.classNames.heightAutoObserverWrapperEl),this.heightAutoObserverEl=this.el.querySelector("."+this.classNames.heightAutoObserverEl),this.axis.x.track.el=this.findChild(this.el,"."+this.classNames.track+"."+this.classNames.horizontal),this.axis.y.track.el=this.findChild(this.el,"."+this.classNames.track+"."+this.classNames.vertical);else{for(this.wrapperEl=document.createElement("div"),this.contentWrapperEl=document.createElement("div"),this.offsetEl=document.createElement("div"),this.maskEl=document.createElement("div"),this.contentEl=document.createElement("div"),this.placeholderEl=document.createElement("div"),this.heightAutoObserverWrapperEl=document.createElement("div"),this.heightAutoObserverEl=document.createElement("div"),this.wrapperEl.classList.add(this.classNames.wrapper),this.contentWrapperEl.classList.add(this.classNames.contentWrapper),this.offsetEl.classList.add(this.classNames.offset),this.maskEl.classList.add(this.classNames.mask),this.contentEl.classList.add(this.classNames.contentEl),this.placeholderEl.classList.add(this.classNames.placeholder),this.heightAutoObserverWrapperEl.classList.add(this.classNames.heightAutoObserverWrapperEl),this.heightAutoObserverEl.classList.add(this.classNames.heightAutoObserverEl);this.el.firstChild;)this.contentEl.appendChild(this.el.firstChild);this.contentWrapperEl.appendChild(this.contentEl),this.offsetEl.appendChild(this.contentWrapperEl),this.maskEl.appendChild(this.offsetEl),this.heightAutoObserverWrapperEl.appendChild(this.heightAutoObserverEl),this.wrapperEl.appendChild(this.heightAutoObserverWrapperEl),this.wrapperEl.appendChild(this.maskEl),this.wrapperEl.appendChild(this.placeholderEl),this.el.appendChild(this.wrapperEl)}if(!this.axis.x.track.el||!this.axis.y.track.el){var t=document.createElement("div"),n=document.createElement("div");t.classList.add(this.classNames.track),n.classList.add(this.classNames.scrollbar),t.appendChild(n),this.axis.x.track.el=t.cloneNode(!0),this.axis.x.track.el.classList.add(this.classNames.horizontal),this.axis.y.track.el=t.cloneNode(!0),this.axis.y.track.el.classList.add(this.classNames.vertical),this.el.appendChild(this.axis.x.track.el),this.el.appendChild(this.axis.y.track.el)}this.axis.x.scrollbar.el=this.axis.x.track.el.querySelector("."+this.classNames.scrollbar),this.axis.y.scrollbar.el=this.axis.y.track.el.querySelector("."+this.classNames.scrollbar),this.options.autoHide||(this.axis.x.scrollbar.el.classList.add(this.classNames.visible),this.axis.y.scrollbar.el.classList.add(this.classNames.visible)),this.el.setAttribute("data-simplebar","init")},t.initListeners=function(){var e=this,t=R(this.el);this.options.autoHide&&this.el.addEventListener("mouseenter",this.onMouseEnter),["mousedown","click","dblclick"].forEach((function(t){e.el.addEventListener(t,e.onPointerEvent,!0)})),["touchstart","touchend","touchmove"].forEach((function(t){e.el.addEventListener(t,e.onPointerEvent,{capture:!0,passive:!0})})),this.el.addEventListener("mousemove",this.onMouseMove),this.el.addEventListener("mouseleave",this.onMouseLeave),this.contentWrapperEl.addEventListener("scroll",this.onScroll),t.addEventListener("resize",this.onWindowResize);var n=!1;this.resizeObserver=new(t.ResizeObserver||C)((function(){n&&e.recalculate()})),this.resizeObserver.observe(this.el),this.resizeObserver.observe(this.contentEl),t.requestAnimationFrame((function(){n=!0})),this.mutationObserver=new t.MutationObserver(this.recalculate),this.mutationObserver.observe(this.contentEl,{childList:!0,subtree:!0,characterData:!0})},t.recalculate=function(){var e=R(this.el);this.elStyles=e.getComputedStyle(this.el),this.isRtl="rtl"===this.elStyles.direction;var t=this.heightAutoObserverEl.offsetHeight<=1,n=this.heightAutoObserverEl.offsetWidth<=1,i=this.contentEl.offsetWidth,r=this.contentWrapperEl.offsetWidth,s=this.elStyles.overflowX,o=this.elStyles.overflowY;this.contentEl.style.padding=this.elStyles.paddingTop+" "+this.elStyles.paddingRight+" "+this.elStyles.paddingBottom+" "+this.elStyles.paddingLeft,this.wrapperEl.style.margin="-"+this.elStyles.paddingTop+" -"+this.elStyles.paddingRight+" -"+this.elStyles.paddingBottom+" -"+this.elStyles.paddingLeft;var a=this.contentEl.scrollHeight,c=this.contentEl.scrollWidth;this.contentWrapperEl.style.height=t?"auto":"100%",this.placeholderEl.style.width=n?i+"px":"auto",this.placeholderEl.style.height=a+"px";var l=this.contentWrapperEl.offsetHeight;this.axis.x.isOverflowing=c>i,this.axis.y.isOverflowing=a>l,this.axis.x.isOverflowing="hidden"!==s&&this.axis.x.isOverflowing,this.axis.y.isOverflowing="hidden"!==o&&this.axis.y.isOverflowing,this.axis.x.forceVisible="x"===this.options.forceVisible||!0===this.options.forceVisible,this.axis.y.forceVisible="y"===this.options.forceVisible||!0===this.options.forceVisible,this.hideNativeScrollbar();var u=this.axis.x.isOverflowing?this.scrollbarWidth:0;this.axis.x.isOverflowing=this.axis.x.isOverflowing&&c>r-(this.axis.y.isOverflowing?this.scrollbarWidth:0),this.axis.y.isOverflowing=this.axis.y.isOverflowing&&a>l-u,this.axis.x.scrollbar.size=this.getScrollbarSize("x"),this.axis.y.scrollbar.size=this.getScrollbarSize("y"),this.axis.x.scrollbar.el.style.width=this.axis.x.scrollbar.size+"px",this.axis.y.scrollbar.el.style.height=this.axis.y.scrollbar.size+"px",this.positionScrollbar("x"),this.positionScrollbar("y"),this.toggleTrackVisibility("x"),this.toggleTrackVisibility("y")},t.getScrollbarSize=function(e){if(void 0===e&&(e="y"),!this.axis[e].isOverflowing)return 0;var t,n=this.axis[e].track.el[this.axis[e].offsetSizeAttr];return t=Math.max(~~(n/this.contentEl[this.axis[e].scrollSizeAttr]*n),this.options.scrollbarMinSize),this.options.scrollbarMaxSize&&(t=Math.min(t,this.options.scrollbarMaxSize)),t},t.positionScrollbar=function(t){if(void 0===t&&(t="y"),this.axis[t].isOverflowing){var n=this.contentWrapperEl[this.axis[t].scrollSizeAttr],i=this.axis[t].track.el[this.axis[t].offsetSizeAttr],r=parseInt(this.elStyles[this.axis[t].sizeAttr],10),s=this.axis[t].scrollbar,o=this.contentWrapperEl[this.axis[t].scrollOffsetAttr],a=~~((o="x"===t&&this.isRtl&&e.getRtlHelpers().isRtlScrollingInverted?-o:o)/(n-r)*(i-s.size));a="x"===t&&this.isRtl&&e.getRtlHelpers().isRtlScrollbarInverted?a+(i-s.size):a,s.el.style.transform="x"===t?"translate3d("+a+"px, 0, 0)":"translate3d(0, "+a+"px, 0)"}},t.toggleTrackVisibility=function(e){void 0===e&&(e="y");var t=this.axis[e].track.el,n=this.axis[e].scrollbar.el;this.axis[e].isOverflowing||this.axis[e].forceVisible?(t.style.visibility="visible",this.contentWrapperEl.style[this.axis[e].overflowAttr]="scroll"):(t.style.visibility="hidden",this.contentWrapperEl.style[this.axis[e].overflowAttr]="hidden"),n.style.display=this.axis[e].isOverflowing?"block":"none"},t.hideNativeScrollbar=function(){this.offsetEl.style[this.isRtl?"left":"right"]=this.axis.y.isOverflowing||this.axis.y.forceVisible?"-"+this.scrollbarWidth+"px":0,this.offsetEl.style.bottom=this.axis.x.isOverflowing||this.axis.x.forceVisible?"-"+this.scrollbarWidth+"px":0},t.onMouseMoveForAxis=function(e){void 0===e&&(e="y"),this.axis[e].track.rect=this.axis[e].track.el.getBoundingClientRect(),this.axis[e].scrollbar.rect=this.axis[e].scrollbar.el.getBoundingClientRect(),this.isWithinBounds(this.axis[e].scrollbar.rect)?this.axis[e].scrollbar.el.classList.add(this.classNames.hover):this.axis[e].scrollbar.el.classList.remove(this.classNames.hover),this.isWithinBounds(this.axis[e].track.rect)?(this.showScrollbar(e),this.axis[e].track.el.classList.add(this.classNames.hover)):this.axis[e].track.el.classList.remove(this.classNames.hover)},t.onMouseLeaveForAxis=function(e){void 0===e&&(e="y"),this.axis[e].track.el.classList.remove(this.classNames.hover),this.axis[e].scrollbar.el.classList.remove(this.classNames.hover)},t.showScrollbar=function(e){void 0===e&&(e="y"),this.axis[e].isVisible||(this.axis[e].scrollbar.el.classList.add(this.classNames.visible),this.axis[e].isVisible=!0),this.options.autoHide&&this.hideScrollbars()},t.onDragStart=function(e,t){void 0===t&&(t="y");var n=E(this.el),i=R(this.el);this.axis[t].dragOffset=("y"===t?e.pageY:e.pageX)-this.axis[t].scrollbar.rect[this.axis[t].offsetAttr],this.draggedAxis=t,this.el.classList.add(this.classNames.dragging),n.addEventListener("mousemove",this.drag,!0),n.addEventListener("mouseup",this.onEndDrag,!0),null===this.removePreventClickId?(n.addEventListener("click",this.preventClick,!0),n.addEventListener("dblclick",this.preventClick,!0)):(i.clearTimeout(this.removePreventClickId),this.removePreventClickId=null)},t.onTrackClick=function(e,t){var n=this;if(void 0===t&&(t="y"),this.options.clickOnTrack){var i=R(this.el);this.axis[t].scrollbar.rect=this.axis[t].scrollbar.el.getBoundingClientRect();var r=this.axis[t].scrollbar.rect[this.axis[t].offsetAttr],s=parseInt(this.elStyles[this.axis[t].sizeAttr],10),o=this.contentWrapperEl[this.axis[t].scrollOffsetAttr],a=("y"===t?this.mouseY-r:this.mouseX-r)<0?-1:1,c=-1===a?o-s:o+s;!function e(){var r,s;-1===a?o>c&&(n.contentWrapperEl.scrollTo(((r={})[n.axis[t].offsetAttr]=o-=n.options.clickOnTrackSpeed,r)),i.requestAnimationFrame(e)):o=e.left&&this.mouseX<=e.left+e.width&&this.mouseY>=e.top&&this.mouseY<=e.top+e.height},t.findChild=function(e,t){var n=e.matches||e.webkitMatchesSelector||e.mozMatchesSelector||e.msMatchesSelector;return Array.prototype.filter.call(e.children,(function(e){return n.call(e,t)}))[0]},e}();j.defaultOptions={autoHide:!0,forceVisible:!1,clickOnTrack:!0,clickOnTrackSpeed:40,classNames:{contentEl:"simplebar-content",contentWrapper:"simplebar-content-wrapper",offset:"simplebar-offset",mask:"simplebar-mask",wrapper:"simplebar-wrapper",placeholder:"simplebar-placeholder",scrollbar:"simplebar-scrollbar",track:"simplebar-track",heightAutoObserverWrapperEl:"simplebar-height-auto-observer-wrapper",heightAutoObserverEl:"simplebar-height-auto-observer",visible:"simplebar-visible",horizontal:"simplebar-horizontal",vertical:"simplebar-vertical",hover:"simplebar-hover",dragging:"simplebar-dragging"},scrollbarMinSize:25,scrollbarMaxSize:0,timeout:1e3},j.instances=new WeakMap;var N=j,F=n("8Y7J");const Y=["*"];let z=(()=>{class e{constructor(e){this.elRef=e}ngOnInit(){}ngAfterViewInit(){this.SimpleBar=new N(this.elRef.nativeElement,this.options||{})}ngOnDestroy(){this.SimpleBar.unMount(),this.SimpleBar=null}}return e.\u0275fac=function(t){return new(t||e)(F.Mb(F.m))},e.\u0275cmp=F.Gb({type:e,selectors:[["ngx-simplebar"]],hostAttrs:["data-simplebar","init"],inputs:{options:"options"},ngContentSelectors:Y,decls:13,vars:0,consts:[[1,"simplebar-wrapper"],[1,"simplebar-height-auto-observer-wrapper"],[1,"simplebar-height-auto-observer"],[1,"simplebar-mask"],[1,"simplebar-offset"],[1,"simplebar-content-wrapper"],[1,"simplebar-content"],[1,"simplebar-placeholder"],[1,"simplebar-track","simplebar-horizontal"],[1,"simplebar-scrollbar"],[1,"simplebar-track","simplebar-vertical"]],template:function(e,t){1&e&&(F.oc(),F.Sb(0,"div",0),F.Sb(1,"div",1),F.Nb(2,"div",2),F.Rb(),F.Sb(3,"div",3),F.Sb(4,"div",4),F.Sb(5,"div",5),F.Sb(6,"div",6),F.nc(7),F.Rb(),F.Rb(),F.Rb(),F.Rb(),F.Nb(8,"div",7),F.Rb(),F.Sb(9,"div",8),F.Nb(10,"div",9),F.Rb(),F.Sb(11,"div",10),F.Nb(12,"div",9),F.Rb())},styles:["[data-simplebar]{position:relative;-webkit-box-orient:vertical;-webkit-box-direction:normal;flex-direction:column;flex-wrap:wrap;-webkit-box-pack:start;justify-content:flex-start;align-content:flex-start;-webkit-box-align:start;align-items:flex-start}.simplebar-wrapper{overflow:hidden;width:inherit;height:inherit;max-width:inherit;max-height:inherit}.simplebar-mask{direction:inherit;position:absolute;overflow:hidden;padding:0;margin:0;left:0;top:0;bottom:0;right:0;width:auto!important;height:auto!important;z-index:0}.simplebar-offset{direction:inherit!important;box-sizing:inherit!important;resize:none!important;position:absolute;top:0;left:0;bottom:0;right:0;padding:0;margin:0;-webkit-overflow-scrolling:touch}.simplebar-content-wrapper{direction:inherit;box-sizing:border-box!important;position:relative;display:block;height:100%;width:auto;max-width:100%;max-height:100%;scrollbar-width:none;-ms-overflow-style:none}.simplebar-content-wrapper::-webkit-scrollbar,.simplebar-hide-scrollbar::-webkit-scrollbar{width:0;height:0}.simplebar-content:after,.simplebar-content:before{content:' ';display:table}.simplebar-placeholder{max-height:100%;max-width:100%;width:100%;pointer-events:none}.simplebar-height-auto-observer-wrapper{box-sizing:inherit!important;height:100%;width:100%;max-width:1px;position:relative;float:left;max-height:1px;overflow:hidden;z-index:-1;padding:0;margin:0;pointer-events:none;-webkit-box-flex:inherit;flex-grow:inherit;flex-shrink:0;flex-basis:0}.simplebar-height-auto-observer{box-sizing:inherit;display:block;opacity:0;position:absolute;top:0;left:0;height:1000%;width:1000%;min-height:1px;min-width:1px;overflow:hidden;pointer-events:none;z-index:-1}.simplebar-track{z-index:1;position:absolute;right:0;bottom:0;pointer-events:none;overflow:hidden}[data-simplebar].simplebar-dragging .simplebar-content{pointer-events:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-select:none}[data-simplebar].simplebar-dragging .simplebar-track{pointer-events:all}.simplebar-scrollbar{position:absolute;left:0;right:0;min-height:10px}.simplebar-scrollbar:before{position:absolute;content:'';background:#000;border-radius:7px;left:2px;right:2px;opacity:0;-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.simplebar-scrollbar.simplebar-visible:before{opacity:.5;-webkit-transition:opacity linear;transition:opacity linear}.simplebar-track.simplebar-vertical{top:0;width:11px}.simplebar-track.simplebar-vertical .simplebar-scrollbar:before{top:2px;bottom:2px}.simplebar-track.simplebar-horizontal{left:0;height:11px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before{height:100%;left:2px;right:2px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar{right:auto;left:0;top:2px;height:7px;min-height:0;min-width:10px;width:auto}[data-simplebar-direction=rtl] .simplebar-track.simplebar-vertical{right:auto;left:0}.hs-dummy-scrollbar-size{direction:rtl;position:fixed;opacity:0;visibility:hidden;height:500px;width:500px;overflow-y:hidden;overflow-x:scroll}.simplebar-hide-scrollbar{position:fixed;left:0;visibility:hidden;overflow-y:scroll;scrollbar-width:none;-ms-overflow-style:none}","ngx-simplebar{display:block}"],encapsulation:2}),e})(),$=(()=>{class e{}return e.\u0275mod=F.Kb({type:e}),e.\u0275inj=F.Jb({factory:function(t){return new(t||e)},imports:[[]]}),e})()},WJ6P:function(e,t,n){"use strict";t.a=function(){return[]}},WJkJ:function(e,t){e.exports="\t\n\v\f\r \xa0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff"},WKiH:function(e,t,n){var i=n("HYAF"),r="["+n("WJkJ")+"]",s=RegExp("^"+r+r+"*"),o=RegExp(r+r+"*$"),a=function(e){return function(t){var n=String(i(t));return 1&e&&(n=n.replace(s,"")),2&e&&(n=n.replace(o,"")),n}};e.exports={start:a(1),end:a(2),trim:a(3)}},WMd4:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("EY2u"),r=n("LRne"),s=n("z6cu");let o=(()=>{class e{constructor(e,t,n){this.kind=e,this.value=t,this.error=n,this.hasValue="N"===e}observe(e){switch(this.kind){case"N":return e.next&&e.next(this.value);case"E":return e.error&&e.error(this.error);case"C":return e.complete&&e.complete()}}do(e,t,n){switch(this.kind){case"N":return e&&e(this.value);case"E":return t&&t(this.error);case"C":return n&&n()}}accept(e,t,n){return e&&"function"==typeof e.next?this.observe(e):this.do(e,t,n)}toObservable(){switch(this.kind){case"N":return Object(r.a)(this.value);case"E":return Object(s.a)(this.error);case"C":return Object(i.b)()}throw new Error("unexpected notification kind value")}static createNext(t){return void 0!==t?new e("N",t):e.undefinedValueNotification}static createError(t){return new e("E",void 0,t)}static createComplete(){return e.completeNotification}}return e.completeNotification=new e("C"),e.undefinedValueNotification=new e("N",void 0),e})()},WOAq:function(e,t,n){"use strict";(function(e){var i=n("Ju5/"),r=n("L3Qv"),s="object"==typeof exports&&exports&&!exports.nodeType&&exports,o=s&&"object"==typeof e&&e&&!e.nodeType&&e,a=o&&o.exports===s?i.a.Buffer:void 0;t.a=(a?a.isBuffer:void 0)||r.a}).call(this,n("3UD+")(e))},WYrj:function(e,t,n){!function(e){"use strict";var t=["\u0796\u07ac\u0782\u07aa\u0787\u07a6\u0783\u07a9","\u078a\u07ac\u0784\u07b0\u0783\u07aa\u0787\u07a6\u0783\u07a9","\u0789\u07a7\u0783\u07a8\u0797\u07aa","\u0787\u07ad\u0795\u07b0\u0783\u07a9\u078d\u07aa","\u0789\u07ad","\u0796\u07ab\u0782\u07b0","\u0796\u07aa\u078d\u07a6\u0787\u07a8","\u0787\u07af\u078e\u07a6\u0790\u07b0\u0793\u07aa","\u0790\u07ac\u0795\u07b0\u0793\u07ac\u0789\u07b0\u0784\u07a6\u0783\u07aa","\u0787\u07ae\u0786\u07b0\u0793\u07af\u0784\u07a6\u0783\u07aa","\u0782\u07ae\u0788\u07ac\u0789\u07b0\u0784\u07a6\u0783\u07aa","\u0791\u07a8\u0790\u07ac\u0789\u07b0\u0784\u07a6\u0783\u07aa"],n=["\u0787\u07a7\u078b\u07a8\u0787\u07b0\u078c\u07a6","\u0780\u07af\u0789\u07a6","\u0787\u07a6\u0782\u07b0\u078e\u07a7\u0783\u07a6","\u0784\u07aa\u078b\u07a6","\u0784\u07aa\u0783\u07a7\u0790\u07b0\u078a\u07a6\u078c\u07a8","\u0780\u07aa\u0786\u07aa\u0783\u07aa","\u0780\u07ae\u0782\u07a8\u0780\u07a8\u0783\u07aa"];e.defineLocale("dv",{months:t,monthsShort:t,weekdays:n,weekdaysShort:n,weekdaysMin:"\u0787\u07a7\u078b\u07a8_\u0780\u07af\u0789\u07a6_\u0787\u07a6\u0782\u07b0_\u0784\u07aa\u078b\u07a6_\u0784\u07aa\u0783\u07a7_\u0780\u07aa\u0786\u07aa_\u0780\u07ae\u0782\u07a8".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/\u0789\u0786|\u0789\u078a/,isPM:function(e){return"\u0789\u078a"===e},meridiem:function(e,t,n){return e<12?"\u0789\u0786":"\u0789\u078a"},calendar:{sameDay:"[\u0789\u07a8\u0787\u07a6\u078b\u07aa] LT",nextDay:"[\u0789\u07a7\u078b\u07a6\u0789\u07a7] LT",nextWeek:"dddd LT",lastDay:"[\u0787\u07a8\u0787\u07b0\u0794\u07ac] LT",lastWeek:"[\u078a\u07a7\u0787\u07a8\u078c\u07aa\u0788\u07a8] dddd LT",sameElse:"L"},relativeTime:{future:"\u078c\u07ac\u0783\u07ad\u078e\u07a6\u0787\u07a8 %s",past:"\u0786\u07aa\u0783\u07a8\u0782\u07b0 %s",s:"\u0790\u07a8\u0786\u07aa\u0782\u07b0\u078c\u07aa\u0786\u07ae\u0785\u07ac\u0787\u07b0",ss:"d% \u0790\u07a8\u0786\u07aa\u0782\u07b0\u078c\u07aa",m:"\u0789\u07a8\u0782\u07a8\u0793\u07ac\u0787\u07b0",mm:"\u0789\u07a8\u0782\u07a8\u0793\u07aa %d",h:"\u078e\u07a6\u0791\u07a8\u0787\u07a8\u0783\u07ac\u0787\u07b0",hh:"\u078e\u07a6\u0791\u07a8\u0787\u07a8\u0783\u07aa %d",d:"\u078b\u07aa\u0788\u07a6\u0780\u07ac\u0787\u07b0",dd:"\u078b\u07aa\u0788\u07a6\u0790\u07b0 %d",M:"\u0789\u07a6\u0780\u07ac\u0787\u07b0",MM:"\u0789\u07a6\u0790\u07b0 %d",y:"\u0787\u07a6\u0780\u07a6\u0783\u07ac\u0787\u07b0",yy:"\u0787\u07a6\u0780\u07a6\u0783\u07aa %d"},preparse:function(e){return e.replace(/\u060c/g,",")},postformat:function(e){return e.replace(/,/g,"\u060c")},week:{dow:7,doy:12}})}(n("wd/R"))},Wv91:function(e,t,n){!function(e){"use strict";var t={1:"'inji",5:"'inji",8:"'inji",70:"'inji",80:"'inji",2:"'nji",7:"'nji",20:"'nji",50:"'nji",3:"'\xfcnji",4:"'\xfcnji",100:"'\xfcnji",6:"'njy",9:"'unjy",10:"'unjy",30:"'unjy",60:"'ynjy",90:"'ynjy"};e.defineLocale("tk",{months:"\xddanwar_Fewral_Mart_Aprel_Ma\xfd_I\xfdun_I\xfdul_Awgust_Sent\xfdabr_Okt\xfdabr_No\xfdabr_Dekabr".split("_"),monthsShort:"\xddan_Few_Mar_Apr_Ma\xfd_I\xfdn_I\xfdl_Awg_Sen_Okt_No\xfd_Dek".split("_"),weekdays:"\xddek\u015fenbe_Du\u015fenbe_Si\u015fenbe_\xc7ar\u015fenbe_Pen\u015fenbe_Anna_\u015eenbe".split("_"),weekdaysShort:"\xddek_Du\u015f_Si\u015f_\xc7ar_Pen_Ann_\u015een".split("_"),weekdaysMin:"\xddk_D\u015f_S\u015f_\xc7r_Pn_An_\u015en".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bug\xfcn sagat] LT",nextDay:"[ertir sagat] LT",nextWeek:"[indiki] dddd [sagat] LT",lastDay:"[d\xfc\xfdn] LT",lastWeek:"[ge\xe7en] dddd [sagat] LT",sameElse:"L"},relativeTime:{future:"%s so\u0148",past:"%s \xf6\u0148",s:"birn\xe4\xe7e sekunt",m:"bir minut",mm:"%d minut",h:"bir sagat",hh:"%d sagat",d:"bir g\xfcn",dd:"%d g\xfcn",M:"bir a\xfd",MM:"%d a\xfd",y:"bir \xfdyl",yy:"%d \xfdyl"},ordinal:function(e,n){switch(n){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'unjy";var i=e%10;return e+(t[i]||t[e%100-i]||t[e>=100?100:null])}},week:{dow:1,doy:7}})}(n("wd/R"))},WxRl:function(e,t,n){!function(e){"use strict";var t="vas\xe1rnap h\xe9tf\u0151n kedden szerd\xe1n cs\xfct\xf6rt\xf6k\xf6n p\xe9nteken szombaton".split(" ");function n(e,t,n,i){var r=e;switch(n){case"s":return i||t?"n\xe9h\xe1ny m\xe1sodperc":"n\xe9h\xe1ny m\xe1sodperce";case"ss":return r+(i||t)?" m\xe1sodperc":" m\xe1sodperce";case"m":return"egy"+(i||t?" perc":" perce");case"mm":return r+(i||t?" perc":" perce");case"h":return"egy"+(i||t?" \xf3ra":" \xf3r\xe1ja");case"hh":return r+(i||t?" \xf3ra":" \xf3r\xe1ja");case"d":return"egy"+(i||t?" nap":" napja");case"dd":return r+(i||t?" nap":" napja");case"M":return"egy"+(i||t?" h\xf3nap":" h\xf3napja");case"MM":return r+(i||t?" h\xf3nap":" h\xf3napja");case"y":return"egy"+(i||t?" \xe9v":" \xe9ve");case"yy":return r+(i||t?" \xe9v":" \xe9ve")}return""}function i(e){return(e?"":"[m\xfalt] ")+"["+t[this.day()]+"] LT[-kor]"}e.defineLocale("hu",{months:"janu\xe1r_febru\xe1r_m\xe1rcius_\xe1prilis_m\xe1jus_j\xfanius_j\xfalius_augusztus_szeptember_okt\xf3ber_november_december".split("_"),monthsShort:"jan._feb._m\xe1rc._\xe1pr._m\xe1j._j\xfan._j\xfal._aug._szept._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"vas\xe1rnap_h\xe9tf\u0151_kedd_szerda_cs\xfct\xf6rt\xf6k_p\xe9ntek_szombat".split("_"),weekdaysShort:"vas_h\xe9t_kedd_sze_cs\xfct_p\xe9n_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(e){return"u"===e.charAt(1).toLowerCase()},meridiem:function(e,t,n){return e<12?!0===n?"de":"DE":!0===n?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return i.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return i.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s m\xfalva",past:"%s",s:n,ss:n,m:n,mm:n,h:n,hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},X709:function(e,t,n){!function(e){"use strict";e.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"s\xf6ndag_m\xe5ndag_tisdag_onsdag_torsdag_fredag_l\xf6rdag".split("_"),weekdaysShort:"s\xf6n_m\xe5n_tis_ons_tor_fre_l\xf6r".split("_"),weekdaysMin:"s\xf6_m\xe5_ti_on_to_fr_l\xf6".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Ig\xe5r] LT",nextWeek:"[P\xe5] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"f\xf6r %s sedan",s:"n\xe5gra sekunder",ss:"%d sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en m\xe5nad",MM:"%d m\xe5nader",y:"ett \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}(\:e|\:a)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?":e":1===t||2===t?":a":":e")},week:{dow:1,doy:4}})}(n("wd/R"))},XDbj:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("sVev"),r=n("7o/Q");function s(e=c){return t=>t.lift(new o(e))}class o{constructor(e){this.errorFactory=e}call(e,t){return t.subscribe(new a(e,this.errorFactory))}}class a extends r.a{constructor(e,t){super(e),this.errorFactory=t,this.hasValue=!1}_next(e){this.hasValue=!0,this.destination.next(e)}_complete(){if(this.hasValue)return this.destination.complete();{let t;try{t=this.errorFactory()}catch(e){t=e}this.destination.error(t)}}}function c(){return new i.a}},XDpg:function(e,t,n){!function(e){"use strict";e.defineLocale("zh-cn",{months:"\u4e00\u6708_\u4e8c\u6708_\u4e09\u6708_\u56db\u6708_\u4e94\u6708_\u516d\u6708_\u4e03\u6708_\u516b\u6708_\u4e5d\u6708_\u5341\u6708_\u5341\u4e00\u6708_\u5341\u4e8c\u6708".split("_"),monthsShort:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),weekdays:"\u661f\u671f\u65e5_\u661f\u671f\u4e00_\u661f\u671f\u4e8c_\u661f\u671f\u4e09_\u661f\u671f\u56db_\u661f\u671f\u4e94_\u661f\u671f\u516d".split("_"),weekdaysShort:"\u5468\u65e5_\u5468\u4e00_\u5468\u4e8c_\u5468\u4e09_\u5468\u56db_\u5468\u4e94_\u5468\u516d".split("_"),weekdaysMin:"\u65e5_\u4e00_\u4e8c_\u4e09_\u56db_\u4e94_\u516d".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY\u5e74M\u6708D\u65e5",LLL:"YYYY\u5e74M\u6708D\u65e5Ah\u70b9mm\u5206",LLLL:"YYYY\u5e74M\u6708D\u65e5ddddAh\u70b9mm\u5206",l:"YYYY/M/D",ll:"YYYY\u5e74M\u6708D\u65e5",lll:"YYYY\u5e74M\u6708D\u65e5 HH:mm",llll:"YYYY\u5e74M\u6708D\u65e5dddd HH:mm"},meridiemParse:/\u51cc\u6668|\u65e9\u4e0a|\u4e0a\u5348|\u4e2d\u5348|\u4e0b\u5348|\u665a\u4e0a/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u51cc\u6668"===t||"\u65e9\u4e0a"===t||"\u4e0a\u5348"===t?e:"\u4e0b\u5348"===t||"\u665a\u4e0a"===t?e+12:e>=11?e:e+12},meridiem:function(e,t,n){var i=100*e+t;return i<600?"\u51cc\u6668":i<900?"\u65e9\u4e0a":i<1130?"\u4e0a\u5348":i<1230?"\u4e2d\u5348":i<1800?"\u4e0b\u5348":"\u665a\u4e0a"},calendar:{sameDay:"[\u4eca\u5929]LT",nextDay:"[\u660e\u5929]LT",nextWeek:function(e){return e.week()!==this.week()?"[\u4e0b]dddLT":"[\u672c]dddLT"},lastDay:"[\u6628\u5929]LT",lastWeek:function(e){return this.week()!==e.week()?"[\u4e0a]dddLT":"[\u672c]dddLT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(\u65e5|\u6708|\u5468)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"\u65e5";case"M":return e+"\u6708";case"w":case"W":return e+"\u5468";default:return e}},relativeTime:{future:"%s\u540e",past:"%s\u524d",s:"\u51e0\u79d2",ss:"%d \u79d2",m:"1 \u5206\u949f",mm:"%d \u5206\u949f",h:"1 \u5c0f\u65f6",hh:"%d \u5c0f\u65f6",d:"1 \u5929",dd:"%d \u5929",w:"1 \u5468",ww:"%d \u5468",M:"1 \u4e2a\u6708",MM:"%d \u4e2a\u6708",y:"1 \u5e74",yy:"%d \u5e74"},week:{dow:1,doy:4}})}(n("wd/R"))},XFyV:function(e,t,n){"use strict";n.d(t,"a",(function(){return l}));var i=n("oxzT"),r=n("8Y7J"),s=n("G0yt"),o=n("SVse");const a=function(e,t){return[e,t]},c=["*"];let l=(()=>{class e{constructor(){this.icons=i.a}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=r.Gb({type:e,selectors:[["cd-loading-panel"]],ngContentSelectors:c,decls:4,vars:5,consts:[["type","info",3,"dismissible"],["aria-hidden","true",1,"mr-2",3,"ngClass"]],template:function(e,t){1&e&&(r.oc(),r.Sb(0,"ngb-alert",0),r.Sb(1,"strong"),r.Nb(2,"i",1),r.Rb(),r.nc(3),r.Rb()),2&e&&(r.pc("dismissible",!1),r.yb(2),r.pc("ngClass",r.vc(2,a,t.icons.spinner,t.icons.spin)))},directives:[s.b,o.p],styles:[""]}),e})()},XGwC:function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},XLvN:function(e,t,n){!function(e){"use strict";e.defineLocale("te",{months:"\u0c1c\u0c28\u0c35\u0c30\u0c3f_\u0c2b\u0c3f\u0c2c\u0c4d\u0c30\u0c35\u0c30\u0c3f_\u0c2e\u0c3e\u0c30\u0c4d\u0c1a\u0c3f_\u0c0f\u0c2a\u0c4d\u0c30\u0c3f\u0c32\u0c4d_\u0c2e\u0c47_\u0c1c\u0c42\u0c28\u0c4d_\u0c1c\u0c41\u0c32\u0c48_\u0c06\u0c17\u0c38\u0c4d\u0c1f\u0c41_\u0c38\u0c46\u0c2a\u0c4d\u0c1f\u0c46\u0c02\u0c2c\u0c30\u0c4d_\u0c05\u0c15\u0c4d\u0c1f\u0c4b\u0c2c\u0c30\u0c4d_\u0c28\u0c35\u0c02\u0c2c\u0c30\u0c4d_\u0c21\u0c3f\u0c38\u0c46\u0c02\u0c2c\u0c30\u0c4d".split("_"),monthsShort:"\u0c1c\u0c28._\u0c2b\u0c3f\u0c2c\u0c4d\u0c30._\u0c2e\u0c3e\u0c30\u0c4d\u0c1a\u0c3f_\u0c0f\u0c2a\u0c4d\u0c30\u0c3f._\u0c2e\u0c47_\u0c1c\u0c42\u0c28\u0c4d_\u0c1c\u0c41\u0c32\u0c48_\u0c06\u0c17._\u0c38\u0c46\u0c2a\u0c4d._\u0c05\u0c15\u0c4d\u0c1f\u0c4b._\u0c28\u0c35._\u0c21\u0c3f\u0c38\u0c46.".split("_"),monthsParseExact:!0,weekdays:"\u0c06\u0c26\u0c3f\u0c35\u0c3e\u0c30\u0c02_\u0c38\u0c4b\u0c2e\u0c35\u0c3e\u0c30\u0c02_\u0c2e\u0c02\u0c17\u0c33\u0c35\u0c3e\u0c30\u0c02_\u0c2c\u0c41\u0c27\u0c35\u0c3e\u0c30\u0c02_\u0c17\u0c41\u0c30\u0c41\u0c35\u0c3e\u0c30\u0c02_\u0c36\u0c41\u0c15\u0c4d\u0c30\u0c35\u0c3e\u0c30\u0c02_\u0c36\u0c28\u0c3f\u0c35\u0c3e\u0c30\u0c02".split("_"),weekdaysShort:"\u0c06\u0c26\u0c3f_\u0c38\u0c4b\u0c2e_\u0c2e\u0c02\u0c17\u0c33_\u0c2c\u0c41\u0c27_\u0c17\u0c41\u0c30\u0c41_\u0c36\u0c41\u0c15\u0c4d\u0c30_\u0c36\u0c28\u0c3f".split("_"),weekdaysMin:"\u0c06_\u0c38\u0c4b_\u0c2e\u0c02_\u0c2c\u0c41_\u0c17\u0c41_\u0c36\u0c41_\u0c36".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[\u0c28\u0c47\u0c21\u0c41] LT",nextDay:"[\u0c30\u0c47\u0c2a\u0c41] LT",nextWeek:"dddd, LT",lastDay:"[\u0c28\u0c3f\u0c28\u0c4d\u0c28] LT",lastWeek:"[\u0c17\u0c24] dddd, LT",sameElse:"L"},relativeTime:{future:"%s \u0c32\u0c4b",past:"%s \u0c15\u0c4d\u0c30\u0c3f\u0c24\u0c02",s:"\u0c15\u0c4a\u0c28\u0c4d\u0c28\u0c3f \u0c15\u0c4d\u0c37\u0c23\u0c3e\u0c32\u0c41",ss:"%d \u0c38\u0c46\u0c15\u0c28\u0c4d\u0c32\u0c41",m:"\u0c12\u0c15 \u0c28\u0c3f\u0c2e\u0c3f\u0c37\u0c02",mm:"%d \u0c28\u0c3f\u0c2e\u0c3f\u0c37\u0c3e\u0c32\u0c41",h:"\u0c12\u0c15 \u0c17\u0c02\u0c1f",hh:"%d \u0c17\u0c02\u0c1f\u0c32\u0c41",d:"\u0c12\u0c15 \u0c30\u0c4b\u0c1c\u0c41",dd:"%d \u0c30\u0c4b\u0c1c\u0c41\u0c32\u0c41",M:"\u0c12\u0c15 \u0c28\u0c46\u0c32",MM:"%d \u0c28\u0c46\u0c32\u0c32\u0c41",y:"\u0c12\u0c15 \u0c38\u0c02\u0c35\u0c24\u0c4d\u0c38\u0c30\u0c02",yy:"%d \u0c38\u0c02\u0c35\u0c24\u0c4d\u0c38\u0c30\u0c3e\u0c32\u0c41"},dayOfMonthOrdinalParse:/\d{1,2}\u0c35/,ordinal:"%d\u0c35",meridiemParse:/\u0c30\u0c3e\u0c24\u0c4d\u0c30\u0c3f|\u0c09\u0c26\u0c2f\u0c02|\u0c2e\u0c27\u0c4d\u0c2f\u0c3e\u0c39\u0c4d\u0c28\u0c02|\u0c38\u0c3e\u0c2f\u0c02\u0c24\u0c4d\u0c30\u0c02/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u0c30\u0c3e\u0c24\u0c4d\u0c30\u0c3f"===t?e<4?e:e+12:"\u0c09\u0c26\u0c2f\u0c02"===t?e:"\u0c2e\u0c27\u0c4d\u0c2f\u0c3e\u0c39\u0c4d\u0c28\u0c02"===t?e>=10?e:e+12:"\u0c38\u0c3e\u0c2f\u0c02\u0c24\u0c4d\u0c30\u0c02"===t?e+12:void 0},meridiem:function(e,t,n){return e<4?"\u0c30\u0c3e\u0c24\u0c4d\u0c30\u0c3f":e<10?"\u0c09\u0c26\u0c2f\u0c02":e<17?"\u0c2e\u0c27\u0c4d\u0c2f\u0c3e\u0c39\u0c4d\u0c28\u0c02":e<20?"\u0c38\u0c3e\u0c2f\u0c02\u0c24\u0c4d\u0c30\u0c02":"\u0c30\u0c3e\u0c24\u0c4d\u0c30\u0c3f"},week:{dow:0,doy:6}})}(n("wd/R"))},XNiG:function(e,t,n){"use strict";n.d(t,"b",(function(){return l})),n.d(t,"a",(function(){return u}));var i=n("HDdC"),r=n("7o/Q"),s=n("quSY"),o=n("9ppp"),a=n("Ylt2"),c=n("2QA8");class l extends r.a{constructor(e){super(e),this.destination=e}}let u=(()=>{class e extends i.a{constructor(){super(),this.observers=[],this.closed=!1,this.isStopped=!1,this.hasError=!1,this.thrownError=null}[c.a](){return new l(this)}lift(e){const t=new d(this,this);return t.operator=e,t}next(e){if(this.closed)throw new o.a;if(!this.isStopped){const{observers:t}=this,n=t.length,i=t.slice();for(let r=0;rnew d(e,t),e})();class d extends u{constructor(e,t){super(),this.destination=e,this.source=t}next(e){const{destination:t}=this;t&&t.next&&t.next(e)}error(e){const{destination:t}=this;t&&t.error&&this.destination.error(e)}complete(){const{destination:e}=this;e&&e.complete&&this.destination.complete()}_subscribe(e){const{source:t}=this;return t?this.source.subscribe(e):s.a.EMPTY}}},XoHu:function(e,t,n){"use strict";function i(e){return null!==e&&"object"==typeof e}n.d(t,"a",(function(){return i}))},XqMk:function(e,t,n){"use strict";var i="object"==typeof global&&global&&global.Object===Object&&global;t.a=i},Y7HM:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("DH7j");function r(e){return!Object(i.a)(e)&&e-parseFloat(e)+1>=0}},Y7yP:function(e,t,n){"use strict";var i,r=n("vJtL"),s=n("Ju5/").a["__core-js_shared__"],o=(i=/[^.]+$/.exec(s&&s.keys&&s.keys.IE_PROTO||""))?"Symbol(src)_1."+i:"",a=n("IzLi"),c=n("dLWn"),l=/^\[object .+?Constructor\]$/,u=RegExp("^"+Function.prototype.toString.call(Object.prototype.hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");t.a=function(e,t){var n=function(e,t){return null==e?void 0:e[t]}(e,t);return function(e){return!(!Object(a.a)(e)||(t=e,o&&o in t))&&(Object(r.a)(e)?u:l).test(Object(c.a)(e));var t}(n)?n:void 0}},YF1G:function(e,t,n){var i=n("xrYK"),r=n("2oRo");e.exports="process"==i(r.process)},YHEm:function(e,t,n){"use strict";t.a=function(e,t){return e===t||e!=e&&t!=t}},YM6B:function(e,t,n){"use strict";var i=n("Y7yP"),r=n("Ju5/"),s=Object(i.a)(r.a,"DataView"),o=n("3cmB"),a=Object(i.a)(r.a,"Promise"),c=Object(i.a)(r.a,"Set"),l=Object(i.a)(r.a,"WeakMap"),u=n("8M4i"),d=n("dLWn"),h="[object Map]",f="[object Promise]",p="[object Set]",m="[object WeakMap]",b="[object DataView]",g=Object(d.a)(s),_=Object(d.a)(o.a),y=Object(d.a)(a),v=Object(d.a)(c),w=Object(d.a)(l),S=u.a;(s&&S(new s(new ArrayBuffer(1)))!=b||o.a&&S(new o.a)!=h||a&&S(a.resolve())!=f||c&&S(new c)!=p||l&&S(new l)!=m)&&(S=function(e){var t=Object(u.a)(e),n="[object Object]"==t?e.constructor:void 0,i=n?Object(d.a)(n):"";if(i)switch(i){case g:return b;case _:return h;case y:return f;case v:return p;case w:return m}return t}),t.a=S},YNrV:function(e,t,n){"use strict";var i=n("g6v/"),r=n("0Dky"),s=n("33Wh"),o=n("dBg+"),a=n("0eef"),c=n("ewvW"),l=n("RK3t"),u=Object.assign,d=Object.defineProperty;e.exports=!u||r((function(){if(i&&1!==u({b:1},u(d({},"a",{enumerable:!0,get:function(){d(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var e={},t={},n=Symbol(),r="abcdefghijklmnopqrst";return e[n]=7,r.split("").forEach((function(e){t[e]=e})),7!=u({},e)[n]||s(u({},t)).join("")!=r}))?function(e,t){for(var n=c(e),r=arguments.length,u=1,d=o.f,h=a.f;r>u;)for(var f,p=l(arguments[u++]),m=d?s(p).concat(d(p)):s(p),b=m.length,g=0;b>g;)f=m[g++],i&&!h.call(p,f)||(n[f]=p[f]);return n}:u},YRex:function(e,t,n){!function(e){"use strict";e.defineLocale("ug-cn",{months:"\u064a\u0627\u0646\u06cb\u0627\u0631_\u0641\u06d0\u06cb\u0631\u0627\u0644_\u0645\u0627\u0631\u062a_\u0626\u0627\u067e\u0631\u06d0\u0644_\u0645\u0627\u064a_\u0626\u0649\u064a\u06c7\u0646_\u0626\u0649\u064a\u06c7\u0644_\u0626\u0627\u06cb\u063a\u06c7\u0633\u062a_\u0633\u06d0\u0646\u062a\u06d5\u0628\u0649\u0631_\u0626\u06c6\u0643\u062a\u06d5\u0628\u0649\u0631_\u0646\u0648\u064a\u0627\u0628\u0649\u0631_\u062f\u06d0\u0643\u0627\u0628\u0649\u0631".split("_"),monthsShort:"\u064a\u0627\u0646\u06cb\u0627\u0631_\u0641\u06d0\u06cb\u0631\u0627\u0644_\u0645\u0627\u0631\u062a_\u0626\u0627\u067e\u0631\u06d0\u0644_\u0645\u0627\u064a_\u0626\u0649\u064a\u06c7\u0646_\u0626\u0649\u064a\u06c7\u0644_\u0626\u0627\u06cb\u063a\u06c7\u0633\u062a_\u0633\u06d0\u0646\u062a\u06d5\u0628\u0649\u0631_\u0626\u06c6\u0643\u062a\u06d5\u0628\u0649\u0631_\u0646\u0648\u064a\u0627\u0628\u0649\u0631_\u062f\u06d0\u0643\u0627\u0628\u0649\u0631".split("_"),weekdays:"\u064a\u06d5\u0643\u0634\u06d5\u0646\u0628\u06d5_\u062f\u06c8\u0634\u06d5\u0646\u0628\u06d5_\u0633\u06d5\u064a\u0634\u06d5\u0646\u0628\u06d5_\u0686\u0627\u0631\u0634\u06d5\u0646\u0628\u06d5_\u067e\u06d5\u064a\u0634\u06d5\u0646\u0628\u06d5_\u062c\u06c8\u0645\u06d5_\u0634\u06d5\u0646\u0628\u06d5".split("_"),weekdaysShort:"\u064a\u06d5_\u062f\u06c8_\u0633\u06d5_\u0686\u0627_\u067e\u06d5_\u062c\u06c8_\u0634\u06d5".split("_"),weekdaysMin:"\u064a\u06d5_\u062f\u06c8_\u0633\u06d5_\u0686\u0627_\u067e\u06d5_\u062c\u06c8_\u0634\u06d5".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY-\u064a\u0649\u0644\u0649M-\u0626\u0627\u064a\u0646\u0649\u06adD-\u0643\u06c8\u0646\u0649",LLL:"YYYY-\u064a\u0649\u0644\u0649M-\u0626\u0627\u064a\u0646\u0649\u06adD-\u0643\u06c8\u0646\u0649\u060c HH:mm",LLLL:"dddd\u060c YYYY-\u064a\u0649\u0644\u0649M-\u0626\u0627\u064a\u0646\u0649\u06adD-\u0643\u06c8\u0646\u0649\u060c HH:mm"},meridiemParse:/\u064a\u06d0\u0631\u0649\u0645 \u0643\u06d0\u0686\u06d5|\u0633\u06d5\u06be\u06d5\u0631|\u0686\u06c8\u0634\u062a\u0649\u0646 \u0628\u06c7\u0631\u06c7\u0646|\u0686\u06c8\u0634|\u0686\u06c8\u0634\u062a\u0649\u0646 \u0643\u06d0\u064a\u0649\u0646|\u0643\u06d5\u0686/,meridiemHour:function(e,t){return 12===e&&(e=0),"\u064a\u06d0\u0631\u0649\u0645 \u0643\u06d0\u0686\u06d5"===t||"\u0633\u06d5\u06be\u06d5\u0631"===t||"\u0686\u06c8\u0634\u062a\u0649\u0646 \u0628\u06c7\u0631\u06c7\u0646"===t?e:"\u0686\u06c8\u0634\u062a\u0649\u0646 \u0643\u06d0\u064a\u0649\u0646"===t||"\u0643\u06d5\u0686"===t?e+12:e>=11?e:e+12},meridiem:function(e,t,n){var i=100*e+t;return i<600?"\u064a\u06d0\u0631\u0649\u0645 \u0643\u06d0\u0686\u06d5":i<900?"\u0633\u06d5\u06be\u06d5\u0631":i<1130?"\u0686\u06c8\u0634\u062a\u0649\u0646 \u0628\u06c7\u0631\u06c7\u0646":i<1230?"\u0686\u06c8\u0634":i<1800?"\u0686\u06c8\u0634\u062a\u0649\u0646 \u0643\u06d0\u064a\u0649\u0646":"\u0643\u06d5\u0686"},calendar:{sameDay:"[\u0628\u06c8\u06af\u06c8\u0646 \u0633\u0627\u0626\u06d5\u062a] LT",nextDay:"[\u0626\u06d5\u062a\u06d5 \u0633\u0627\u0626\u06d5\u062a] LT",nextWeek:"[\u0643\u06d0\u0644\u06d5\u0631\u0643\u0649] dddd [\u0633\u0627\u0626\u06d5\u062a] LT",lastDay:"[\u062a\u06c6\u0646\u06c8\u06af\u06c8\u0646] LT",lastWeek:"[\u0626\u0627\u0644\u062f\u0649\u0646\u0642\u0649] dddd [\u0633\u0627\u0626\u06d5\u062a] LT",sameElse:"L"},relativeTime:{future:"%s \u0643\u06d0\u064a\u0649\u0646",past:"%s \u0628\u06c7\u0631\u06c7\u0646",s:"\u0646\u06d5\u0686\u0686\u06d5 \u0633\u06d0\u0643\u0648\u0646\u062a",ss:"%d \u0633\u06d0\u0643\u0648\u0646\u062a",m:"\u0628\u0649\u0631 \u0645\u0649\u0646\u06c7\u062a",mm:"%d \u0645\u0649\u0646\u06c7\u062a",h:"\u0628\u0649\u0631 \u0633\u0627\u0626\u06d5\u062a",hh:"%d \u0633\u0627\u0626\u06d5\u062a",d:"\u0628\u0649\u0631 \u0643\u06c8\u0646",dd:"%d \u0643\u06c8\u0646",M:"\u0628\u0649\u0631 \u0626\u0627\u064a",MM:"%d \u0626\u0627\u064a",y:"\u0628\u0649\u0631 \u064a\u0649\u0644",yy:"%d \u064a\u0649\u0644"},dayOfMonthOrdinalParse:/\d{1,2}(-\u0643\u06c8\u0646\u0649|-\u0626\u0627\u064a|-\u06be\u06d5\u067e\u062a\u06d5)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"-\u0643\u06c8\u0646\u0649";case"w":case"W":return e+"-\u06be\u06d5\u067e\u062a\u06d5";default:return e}},preparse:function(e){return e.replace(/\u060c/g,",")},postformat:function(e){return e.replace(/,/g,"\u060c")},week:{dow:1,doy:7}})}(n("wd/R"))},Ylt2:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("quSY");class r extends i.a{constructor(e,t){super(),this.subject=e,this.subscriber=t,this.closed=!1}unsubscribe(){if(this.closed)return;this.closed=!0;const e=this.subject,t=e.observers;if(this.subject=null,!t||0===t.length||e.isStopped||e.closed)return;const n=t.indexOf(this.subscriber);-1!==n&&t.splice(n,1)}}},YuTi:function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},Z21x:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("8Y7J"),r=n("sne2"),s=n("SVse"),o=n("ANnk");let a=(()=>{class e{constructor(e,t){this.location=e,this.actionLabels=t,this.backAction=new i.o,this.name=this.actionLabels.CANCEL}back(){0===this.backAction.observers.length?this.location.back():this.backAction.emit()}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(s.m),i.Mb(r.b))},e.\u0275cmp=i.Gb({type:e,selectors:[["cd-back-button"]],inputs:{name:"name"},outputs:{backAction:"backAction"},decls:2,vars:1,consts:[["type","button",1,"btn","btn-light","tc_backButton",3,"click"]],template:function(e,t){1&e&&(i.Sb(0,"button",0),i.gc("click",(function(){return t.back()})),i.Oc(1),i.Rb()),2&e&&(i.yb(1),i.Qc(" ",t.name,"\n"))},directives:[o.a],styles:[""]}),e})()},Z4QM:function(e,t,n){!function(e){"use strict";var t=["\u062c\u0646\u0648\u0631\u064a","\u0641\u064a\u0628\u0631\u0648\u0631\u064a","\u0645\u0627\u0631\u0686","\u0627\u067e\u0631\u064a\u0644","\u0645\u0626\u064a","\u062c\u0648\u0646","\u062c\u0648\u0644\u0627\u0621\u0650","\u0622\u06af\u0633\u067d","\u0633\u064a\u067e\u067d\u0645\u0628\u0631","\u0622\u06aa\u067d\u0648\u0628\u0631","\u0646\u0648\u0645\u0628\u0631","\u068a\u0633\u0645\u0628\u0631"],n=["\u0622\u0686\u0631","\u0633\u0648\u0645\u0631","\u0627\u06b1\u0627\u0631\u0648","\u0627\u0631\u0628\u0639","\u062e\u0645\u064a\u0633","\u062c\u0645\u0639","\u0687\u0646\u0687\u0631"];e.defineLocale("sd",{months:t,monthsShort:t,weekdays:n,weekdaysShort:n,weekdaysMin:n,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd\u060c D MMMM YYYY HH:mm"},meridiemParse:/\u0635\u0628\u062d|\u0634\u0627\u0645/,isPM:function(e){return"\u0634\u0627\u0645"===e},meridiem:function(e,t,n){return e<12?"\u0635\u0628\u062d":"\u0634\u0627\u0645"},calendar:{sameDay:"[\u0627\u0684] LT",nextDay:"[\u0633\u0680\u0627\u06bb\u064a] LT",nextWeek:"dddd [\u0627\u06b3\u064a\u0646 \u0647\u0641\u062a\u064a \u062a\u064a] LT",lastDay:"[\u06aa\u0627\u0644\u0647\u0647] LT",lastWeek:"[\u06af\u0632\u0631\u064a\u0644 \u0647\u0641\u062a\u064a] dddd [\u062a\u064a] LT",sameElse:"L"},relativeTime:{future:"%s \u067e\u0648\u0621",past:"%s \u0627\u06b3",s:"\u0686\u0646\u062f \u0633\u064a\u06aa\u0646\u068a",ss:"%d \u0633\u064a\u06aa\u0646\u068a",m:"\u0647\u06aa \u0645\u0646\u067d",mm:"%d \u0645\u0646\u067d",h:"\u0647\u06aa \u06aa\u0644\u0627\u06aa",hh:"%d \u06aa\u0644\u0627\u06aa",d:"\u0647\u06aa \u068f\u064a\u0646\u0647\u0646",dd:"%d \u068f\u064a\u0646\u0647\u0646",M:"\u0647\u06aa \u0645\u0647\u064a\u0646\u0648",MM:"%d \u0645\u0647\u064a\u0646\u0627",y:"\u0647\u06aa \u0633\u0627\u0644",yy:"%d \u0633\u0627\u0644"},preparse:function(e){return e.replace(/\u060c/g,",")},postformat:function(e){return e.replace(/,/g,"\u060c")},week:{dow:1,doy:4}})}(n("wd/R"))},ZAMP:function(e,t,n){!function(e){"use strict";e.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,t){return 12===e&&(e=0),"pagi"===t?e:"tengahari"===t?e>=11?e:e+12:"petang"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,n){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(n("wd/R"))},ZUHj:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("7o/Q");class r extends i.a{constructor(e,t,n){super(),this.parent=e,this.outerValue=t,this.outerIndex=n,this.index=0}_next(e){this.parent.notifyNext(this.outerValue,e,this.outerIndex,this.index++,this)}_error(e){this.parent.notifyError(e,this),this.unsubscribe()}_complete(){this.parent.notifyComplete(this),this.unsubscribe()}}var s=n("SeVD"),o=n("HDdC");function a(e,t,n,i,a=new r(e,n,i)){if(!a.closed)return t instanceof o.a?t.subscribe(a):Object(s.a)(t)(a)}},ZUd8:function(e,t,n){var i=n("ppGB"),r=n("HYAF"),s=function(e){return function(t,n){var s,o,a=String(r(t)),c=i(n),l=a.length;return c<0||c>=l?e?"":void 0:(s=a.charCodeAt(c))<55296||s>56319||c+1===l||(o=a.charCodeAt(c+1))<56320||o>57343?e?a.charAt(c):s:e?a.slice(c,c+2):o-56320+(s-55296<<10)+65536}};e.exports={codeAt:s(!1),charAt:s(!0)}},Zduo:function(e,t,n){!function(e){"use strict";e.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_a\u016dgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mart_apr_maj_jun_jul_a\u016dg_sept_okt_nov_dec".split("_"),weekdays:"diman\u0109o_lundo_mardo_merkredo_\u0135a\u016ddo_vendredo_sabato".split("_"),weekdaysShort:"dim_lun_mard_merk_\u0135a\u016d_ven_sab".split("_"),weekdaysMin:"di_lu_ma_me_\u0135a_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"[la] D[-an de] MMMM, YYYY",LLL:"[la] D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd[n], [la] D[-an de] MMMM, YYYY HH:mm",llll:"ddd, [la] D[-an de] MMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(e){return"p"===e.charAt(0).toLowerCase()},meridiem:function(e,t,n){return e>11?n?"p.t.m.":"P.T.M.":n?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodia\u016d je] LT",nextDay:"[Morga\u016d je] LT",nextWeek:"dddd[n je] LT",lastDay:"[Hiera\u016d je] LT",lastWeek:"[pasintan] dddd[n je] LT",sameElse:"L"},relativeTime:{future:"post %s",past:"anta\u016d %s",s:"kelkaj sekundoj",ss:"%d sekundoj",m:"unu minuto",mm:"%d minutoj",h:"unu horo",hh:"%d horoj",d:"unu tago",dd:"%d tagoj",M:"unu monato",MM:"%d monatoj",y:"unu jaro",yy:"%d jaroj"},dayOfMonthOrdinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,doy:7}})}(n("wd/R"))},ZfDv:function(e,t,n){var i=n("hh1v"),r=n("6LWA"),s=n("tiKp")("species");e.exports=function(e,t){var n;return r(e)&&("function"!=typeof(n=e.constructor)||n!==Array&&!r(n.prototype)?i(n)&&null===(n=n[s])&&(n=void 0):n=void 0),new(void 0===n?Array:n)(0===t?0:t)}},a0VL:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("8Y7J"),r=n("SVse");let s=(()=>{class e{constructor(e){this.datePipe=e}transform(e){return null===e||""===e?"":this.datePipe.transform(e,"shortDate")+" "+this.datePipe.transform(e,"mediumTime")}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(r.e))},e.\u0275pipe=i.Lb({name:"cdDate",type:e,pure:!0}),e})()},a96k:function(e,t,n){"use strict";n.d(t,"a",(function(){return i}));class i{constructor(e,t,n,i=!0){this.selected=e,this.name=t,this.description=n,this.enabled=i}}},aGrj:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("eIep");function r(e,t){return t?Object(i.a)(()=>e,t):Object(i.a)(()=>e)}},aIdf:function(e,t,n){!function(e){"use strict";function t(e,t,n){return e+" "+function(e,t){return 2===t?function(e){var t={m:"v",b:"v",d:"z"};return void 0===t[e.charAt(0)]?e:t[e.charAt(0)]+e.substring(1)}(e):e}({mm:"munutenn",MM:"miz",dd:"devezh"}[n],e)}var n=[/^gen/i,/^c[\u02bc\']hwe/i,/^meu/i,/^ebr/i,/^mae/i,/^(mez|eve)/i,/^gou/i,/^eos/i,/^gwe/i,/^her/i,/^du/i,/^ker/i],i=/^(genver|c[\u02bc\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu|gen|c[\u02bc\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,r=[/^Su/i,/^Lu/i,/^Me([^r]|$)/i,/^Mer/i,/^Ya/i,/^Gw/i,/^Sa/i];e.defineLocale("br",{months:"Genver_C\u02bchwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_C\u02bchwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Merc\u02bcher_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParse:r,fullWeekdaysParse:[/^sul/i,/^lun/i,/^meurzh/i,/^merc[\u02bc\']her/i,/^yaou/i,/^gwener/i,/^sadorn/i],shortWeekdaysParse:[/^Sul/i,/^Lun/i,/^Meu/i,/^Mer/i,/^Yao/i,/^Gwe/i,/^Sad/i],minWeekdaysParse:r,monthsRegex:i,monthsShortRegex:i,monthsStrictRegex:/^(genver|c[\u02bc\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu)/i,monthsShortStrictRegex:/^(gen|c[\u02bc\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,monthsParse:n,longMonthsParse:n,shortMonthsParse:n,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY HH:mm",LLLL:"dddd, D [a viz] MMMM YYYY HH:mm"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warc\u02bchoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Dec\u02bch da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s \u02bczo",s:"un nebeud segondenno\xf9",ss:"%d eilenn",m:"ur vunutenn",mm:t,h:"un eur",hh:"%d eur",d:"un devezh",dd:t,M:"ur miz",MM:t,y:"ur bloaz",yy:function(e){switch(function e(t){return t>9?e(t%10):t}(e)){case 1:case 3:case 4:case 5:case 9:return e+" bloaz";default:return e+" vloaz"}}},dayOfMonthOrdinalParse:/\d{1,2}(a\xf1|vet)/,ordinal:function(e){return e+(1===e?"a\xf1":"vet")},week:{dow:1,doy:4},meridiemParse:/a.m.|g.m./,isPM:function(e){return"g.m."===e},meridiem:function(e,t,n){return e<12?"a.m.":"g.m."}})}(n("wd/R"))},aIsn:function(e,t,n){!function(e){"use strict";e.defineLocale("mi",{months:"Kohi-t\u0101te_Hui-tanguru_Pout\u016b-te-rangi_Paenga-wh\u0101wh\u0101_Haratua_Pipiri_H\u014dngoingoi_Here-turi-k\u014dk\u0101_Mahuru_Whiringa-\u0101-nuku_Whiringa-\u0101-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_H\u014dngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"R\u0101tapu_Mane_T\u016brei_Wenerei_T\u0101ite_Paraire_H\u0101tarei".split("_"),weekdaysShort:"Ta_Ma_T\u016b_We_T\u0101i_Pa_H\u0101".split("_"),weekdaysMin:"Ta_Ma_T\u016b_We_T\u0101i_Pa_H\u0101".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te h\u0113kona ruarua",ss:"%d h\u0113kona",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:1,doy:4}})}(n("wd/R"))},aQkU:function(e,t,n){!function(e){"use strict";e.defineLocale("mk",{months:"\u0458\u0430\u043d\u0443\u0430\u0440\u0438_\u0444\u0435\u0432\u0440\u0443\u0430\u0440\u0438_\u043c\u0430\u0440\u0442_\u0430\u043f\u0440\u0438\u043b_\u043c\u0430\u0458_\u0458\u0443\u043d\u0438_\u0458\u0443\u043b\u0438_\u0430\u0432\u0433\u0443\u0441\u0442_\u0441\u0435\u043f\u0442\u0435\u043c\u0432\u0440\u0438_\u043e\u043a\u0442\u043e\u043c\u0432\u0440\u0438_\u043d\u043e\u0435\u043c\u0432\u0440\u0438_\u0434\u0435\u043a\u0435\u043c\u0432\u0440\u0438".split("_"),monthsShort:"\u0458\u0430\u043d_\u0444\u0435\u0432_\u043c\u0430\u0440_\u0430\u043f\u0440_\u043c\u0430\u0458_\u0458\u0443\u043d_\u0458\u0443\u043b_\u0430\u0432\u0433_\u0441\u0435\u043f_\u043e\u043a\u0442_\u043d\u043e\u0435_\u0434\u0435\u043a".split("_"),weekdays:"\u043d\u0435\u0434\u0435\u043b\u0430_\u043f\u043e\u043d\u0435\u0434\u0435\u043b\u043d\u0438\u043a_\u0432\u0442\u043e\u0440\u043d\u0438\u043a_\u0441\u0440\u0435\u0434\u0430_\u0447\u0435\u0442\u0432\u0440\u0442\u043e\u043a_\u043f\u0435\u0442\u043e\u043a_\u0441\u0430\u0431\u043e\u0442\u0430".split("_"),weekdaysShort:"\u043d\u0435\u0434_\u043f\u043e\u043d_\u0432\u0442\u043e_\u0441\u0440\u0435_\u0447\u0435\u0442_\u043f\u0435\u0442_\u0441\u0430\u0431".split("_"),weekdaysMin:"\u043de_\u043fo_\u0432\u0442_\u0441\u0440_\u0447\u0435_\u043f\u0435_\u0441a".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[\u0414\u0435\u043d\u0435\u0441 \u0432\u043e] LT",nextDay:"[\u0423\u0442\u0440\u0435 \u0432\u043e] LT",nextWeek:"[\u0412\u043e] dddd [\u0432\u043e] LT",lastDay:"[\u0412\u0447\u0435\u0440\u0430 \u0432\u043e] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[\u0418\u0437\u043c\u0438\u043d\u0430\u0442\u0430\u0442\u0430] dddd [\u0432\u043e] LT";case 1:case 2:case 4:case 5:return"[\u0418\u0437\u043c\u0438\u043d\u0430\u0442\u0438\u043e\u0442] dddd [\u0432\u043e] LT"}},sameElse:"L"},relativeTime:{future:"\u0437\u0430 %s",past:"\u043f\u0440\u0435\u0434 %s",s:"\u043d\u0435\u043a\u043e\u043b\u043a\u0443 \u0441\u0435\u043a\u0443\u043d\u0434\u0438",ss:"%d \u0441\u0435\u043a\u0443\u043d\u0434\u0438",m:"\u0435\u0434\u043d\u0430 \u043c\u0438\u043d\u0443\u0442\u0430",mm:"%d \u043c\u0438\u043d\u0443\u0442\u0438",h:"\u0435\u0434\u0435\u043d \u0447\u0430\u0441",hh:"%d \u0447\u0430\u0441\u0430",d:"\u0435\u0434\u0435\u043d \u0434\u0435\u043d",dd:"%d \u0434\u0435\u043d\u0430",M:"\u0435\u0434\u0435\u043d \u043c\u0435\u0441\u0435\u0446",MM:"%d \u043c\u0435\u0441\u0435\u0446\u0438",y:"\u0435\u0434\u043d\u0430 \u0433\u043e\u0434\u0438\u043d\u0430",yy:"%d \u0433\u043e\u0434\u0438\u043d\u0438"},dayOfMonthOrdinalParse:/\d{1,2}-(\u0435\u0432|\u0435\u043d|\u0442\u0438|\u0432\u0438|\u0440\u0438|\u043c\u0438)/,ordinal:function(e){var t=e%10,n=e%100;return 0===e?e+"-\u0435\u0432":0===n?e+"-\u0435\u043d":n>10&&n<20?e+"-\u0442\u0438":1===t?e+"-\u0432\u0438":2===t?e+"-\u0440\u0438":7===t||8===t?e+"-\u043c\u0438":e+"-\u0442\u0438"},week:{dow:1,doy:7}})}(n("wd/R"))},aXbf:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");let o=(()=>{class e{format_number(e,t,n,i=1){if(r.a.isString(e)&&(e=Number(e)),!r.a.isNumber(e))return"-";let s=e<1?0:Math.floor(Math.log(e)/Math.log(t));s=s>=n.length?n.length-1:s;let o=r.a.round(e/Math.pow(t,s),i).toString();return""===o?"-":(""!==n[s]&&(o=`${o} ${n[s]}`),o)}toBytes(e,t=null){const n=["b","k","m","g","t","p","e","z","y"],i=RegExp("^(\\d+(.\\d+)?) ?(["+n.join("")+"]?(b|ib|B/s)?)?$","i").exec(e);if(null===i)return t;let s=parseFloat(i[1]);return r.a.isString(i[3])&&(s*=Math.pow(1024,n.indexOf(i[3].toLowerCase()[0]))),Math.round(s)}toMilliseconds(e){const t=/^\s*(\d+)\s*(ms)?\s*$/i.exec(e);return null!==t?+t[1]:0}toIops(e){const t=/^\s*(\d+)\s*(IOPS)?\s*$/i.exec(e);return null!==t?+t[1]:0}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=s.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},aexS:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("2Vo4"),r=n("jKX/"),s=n("8Y7J");let o=(()=>{class e{constructor(){this.isPwdDisplayedSource=new i.a(!1),this.isPwdDisplayed$=this.isPwdDisplayedSource.asObservable()}set(e,t={},n=!1,i=null,s=!1){localStorage.setItem("dashboard_username",e),localStorage.setItem("dashboard_permissions",JSON.stringify(new r.a(t))),localStorage.setItem("user_pwd_expiration_date",String(i)),localStorage.setItem("user_pwd_update_required",String(s)),localStorage.setItem("sso",String(n))}remove(){localStorage.removeItem("dashboard_username"),localStorage.removeItem("user_pwd_expiration_data"),localStorage.removeItem("user_pwd_update_required")}isLoggedIn(){return null!==localStorage.getItem("dashboard_username")}getUsername(){return localStorage.getItem("dashboard_username")}getPermissions(){return JSON.parse(localStorage.getItem("dashboard_permissions")||JSON.stringify(new r.a({})))}getPwdExpirationDate(){return Number(localStorage.getItem("user_pwd_expiration_date"))}getPwdUpdateRequired(){return"true"===localStorage.getItem("user_pwd_update_required")}isSSO(){return"true"===localStorage.getItem("sso")}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=s.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},afO8:function(e,t,n){var i,r,s,o=n("f5p1"),a=n("2oRo"),c=n("hh1v"),l=n("kRJp"),u=n("UTVS"),d=n("xs3f"),h=n("93I0"),f=n("0BK2"),p="Object already initialized";if(o||d.state){var m=d.state||(d.state=new(0,a.WeakMap)),b=m.get,g=m.has,_=m.set;i=function(e,t){if(g.call(m,e))throw new TypeError(p);return t.facade=e,_.call(m,e,t),t},r=function(e){return b.call(m,e)||{}},s=function(e){return g.call(m,e)}}else{var y=h("state");f[y]=!0,i=function(e,t){if(u(e,y))throw new TypeError(p);return t.facade=e,l(e,y,t),t},r=function(e){return u(e,y)?e[y]:{}},s=function(e){return u(e,y)}}e.exports={set:i,get:r,has:s,enforce:function(e){return s(e)?r(e):i(e,{})},getterFor:function(e){return function(t){var n;if(!c(t)||(n=r(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}}},ajRT:function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var i=n("8Y7J"),r=n("ANnk");const s=[[["",8,"modal-title"]],[["",8,"modal-content"]]],o=[".modal-title",".modal-content"];let a=(()=>{class e{constructor(){this.hide=new i.o}close(){var e;null===(e=this.modalRef)||void 0===e||e.close(),this.hide.emit()}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275cmp=i.Gb({type:e,selectors:[["cd-modal"]],inputs:{modalRef:"modalRef"},outputs:{hide:"hide"},ngContentSelectors:o,decls:7,vars:0,consts:[[1,"modal-header"],[1,"modal-title","float-left"],["type","button","aria-label","Close",1,"close","float-right",3,"click"],["aria-hidden","true"]],template:function(e,t){1&e&&(i.oc(s),i.Sb(0,"div",0),i.Sb(1,"h4",1),i.nc(2),i.Rb(),i.Sb(3,"button",2),i.gc("click",(function(){return t.close()})),i.Sb(4,"span",3),i.Oc(5,"\xd7"),i.Rb(),i.Rb(),i.Rb(),i.nc(6,1))},directives:[r.a],styles:[".modal-header[_ngcontent-%COMP%]{border-radius:5px 5px 0 0}.modal-header[_ngcontent-%COMP%], cd-modal .modal-footer{background-color:#e9ecef;border-bottom:1px solid #ced4da} cd-modal .modal-footer{border-radius:0 0 5px 5px} cd-modal .modal-body{max-height:70vh;overflow-x:hidden;overflow-y:auto}button.close[_ngcontent-%COMP%]{outline:none}"]}),e})()},b1Dy:function(e,t,n){!function(e){"use strict";e.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(n("wd/R"))},b5OY:function(e,t,n){"use strict";n.d(t,"a",(function(){return _}));var i=n("mrSG"),r=n("IheW"),s=n("LRne"),o=n("5+tZ"),a=n("xTzq"),c=n("8Y7J");let l=(()=>{let e=class{constructor(e){this.http=e,this.url="api/perf_counters"}list(){return this.http.get(this.url)}get(e,t){return this.http.get(`${this.url}/${e}/${t}`).pipe(Object(o.a)(e=>Object(s.a)(e.counters)))}};return e.\u0275fac=function(t){return new(t||e)(c.dc(r.b))},e.\u0275prov=c.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e=Object(i.b)([a.a,Object(i.d)("design:paramtypes",[r.b])],e),e})();var u=n("SVse"),d=n("uIqm"),h=n("/NlG"),f=n("o4+5");const p=["valueTpl"];function m(e,t){if(1&e&&(c.Oc(0),c.jc(1,"dimless")),2&e){const e=t.row;c.Rc(" ",c.kc(1,2,e.value)," ",e.unit," ")}}function b(e,t){if(1&e){const e=c.Tb();c.Sb(0,"cd-table",2),c.gc("fetchData",(function(t){return c.Dc(e),c.ic().getCounters(t)})),c.Mc(1,m,2,4,"ng-template",null,3,c.Nc),c.Rb()}if(2&e){const e=c.ic();c.pc("data",e.counters)("columns",e.columns)("autoSave",!1)}}function g(e,t){1&e&&(c.Sb(0,"cd-alert-panel",4),c.Wb(1,5),c.Rb())}let _=(()=>{class e{constructor(e){this.performanceCounterService=e,this.columns=[],this.counters=[]}ngOnInit(){this.columns=[{name:"Name",prop:"name",flexGrow:1},{name:"Description",prop:"description",flexGrow:1},{name:"Value",prop:"value",cellTemplate:this.valueTpl,flexGrow:1}]}getCounters(e){this.performanceCounterService.get(this.serviceType,this.serviceId).subscribe(e=>{this.counters=e},t=>{404===t.status?(t.preventDefault(),this.counters=null):e.error()})}}return e.\u0275fac=function(t){return new(t||e)(c.Mb(l))},e.\u0275cmp=c.Gb({type:e,selectors:[["cd-table-performance-counter"]],viewQuery:function(e,t){var n;1&e&&c.Tc(p,!0),2&e&&c.zc(n=c.hc())&&(t.valueTpl=n.first)},inputs:{serviceType:"serviceType",serviceId:"serviceId"},decls:3,vars:2,consts:function(){return[["columnMode","flex",3,"data","columns","autoSave","fetchData",4,"ngIf","ngIfElse"],["warning",""],["columnMode","flex",3,"data","columns","autoSave","fetchData"],["valueTpl",""],["type","warning"],"Performance counters not available"]},template:function(e,t){if(1&e&&(c.Mc(0,b,3,3,"cd-table",0),c.Mc(1,g,2,0,"ng-template",null,1,c.Nc)),2&e){const e=c.Ac(2);c.pc("ngIf",t.counters)("ngIfElse",e)}},directives:[u.r,d.a,h.a],pipes:[f.a],styles:[""]}),e})()},bHdf:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("5+tZ"),r=n("SpAZ");function s(e=Number.POSITIVE_INFINITY){return Object(i.a)(r.a,e)}},bOMt:function(e,t,n){!function(e){"use strict";e.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"s\xf8ndag_mandag_tirsdag_onsdag_torsdag_fredag_l\xf8rdag".split("_"),weekdaysShort:"s\xf8._ma._ti._on._to._fr._l\xf8.".split("_"),weekdaysMin:"s\xf8_ma_ti_on_to_fr_l\xf8".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i g\xe5r kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",ss:"%d sekunder",m:"ett minutt",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dager",w:"en uke",ww:"%d uker",M:"en m\xe5ned",MM:"%d m\xe5neder",y:"ett \xe5r",yy:"%d \xe5r"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},bOdf:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("5+tZ");function r(e,t){return Object(i.a)(e,t,1)}},bWFh:function(e,t,n){"use strict";var i=n("I+eb"),r=n("2oRo"),s=n("lMq5"),o=n("busE"),a=n("8YOa"),c=n("ImZN"),l=n("GarU"),u=n("hh1v"),d=n("0Dky"),h=n("HH4o"),f=n("1E5z"),p=n("cVYH");e.exports=function(e,t,n){var m=-1!==e.indexOf("Map"),b=-1!==e.indexOf("Weak"),g=m?"set":"add",_=r[e],y=_&&_.prototype,v=_,w={},S=function(e){var t=y[e];o(y,e,"add"==e?function(e){return t.call(this,0===e?0:e),this}:"delete"==e?function(e){return!(b&&!u(e))&&t.call(this,0===e?0:e)}:"get"==e?function(e){return b&&!u(e)?void 0:t.call(this,0===e?0:e)}:"has"==e?function(e){return!(b&&!u(e))&&t.call(this,0===e?0:e)}:function(e,n){return t.call(this,0===e?0:e,n),this})};if(s(e,"function"!=typeof _||!(b||y.forEach&&!d((function(){(new _).entries().next()})))))v=n.getConstructor(t,e,m,g),a.REQUIRED=!0;else if(s(e,!0)){var M=new v,x=M[g](b?{}:-0,1)!=M,k=d((function(){M.has(1)})),D=h((function(e){new _(e)})),T=!b&&d((function(){for(var e=new _,t=5;t--;)e[g](t,t);return!e.has(-0)}));D||((v=t((function(t,n){l(t,v,e);var i=p(new _,t,v);return null!=n&&c(n,i[g],{that:i,AS_ENTRIES:m}),i}))).prototype=y,y.constructor=v),(k||T)&&(S("delete"),S("has"),m&&S("get")),(T||x)&&S(g),b&&y.clear&&delete y.clear}return w[e]=v,i({global:!0,forced:v!=_},w),f(v,e),b||n.setStrong(v,e,m),v}},bXm7:function(e,t,n){!function(e){"use strict";var t={0:"-\u0448\u0456",1:"-\u0448\u0456",2:"-\u0448\u0456",3:"-\u0448\u0456",4:"-\u0448\u0456",5:"-\u0448\u0456",6:"-\u0448\u044b",7:"-\u0448\u0456",8:"-\u0448\u0456",9:"-\u0448\u044b",10:"-\u0448\u044b",20:"-\u0448\u044b",30:"-\u0448\u044b",40:"-\u0448\u044b",50:"-\u0448\u0456",60:"-\u0448\u044b",70:"-\u0448\u0456",80:"-\u0448\u0456",90:"-\u0448\u044b",100:"-\u0448\u0456"};e.defineLocale("kk",{months:"\u049b\u0430\u04a3\u0442\u0430\u0440_\u0430\u049b\u043f\u0430\u043d_\u043d\u0430\u0443\u0440\u044b\u0437_\u0441\u04d9\u0443\u0456\u0440_\u043c\u0430\u043c\u044b\u0440_\u043c\u0430\u0443\u0441\u044b\u043c_\u0448\u0456\u043b\u0434\u0435_\u0442\u0430\u043c\u044b\u0437_\u049b\u044b\u0440\u043a\u04af\u0439\u0435\u043a_\u049b\u0430\u0437\u0430\u043d_\u049b\u0430\u0440\u0430\u0448\u0430_\u0436\u0435\u043b\u0442\u043e\u049b\u0441\u0430\u043d".split("_"),monthsShort:"\u049b\u0430\u04a3_\u0430\u049b\u043f_\u043d\u0430\u0443_\u0441\u04d9\u0443_\u043c\u0430\u043c_\u043c\u0430\u0443_\u0448\u0456\u043b_\u0442\u0430\u043c_\u049b\u044b\u0440_\u049b\u0430\u0437_\u049b\u0430\u0440_\u0436\u0435\u043b".split("_"),weekdays:"\u0436\u0435\u043a\u0441\u0435\u043d\u0431\u0456_\u0434\u04af\u0439\u0441\u0435\u043d\u0431\u0456_\u0441\u0435\u0439\u0441\u0435\u043d\u0431\u0456_\u0441\u04d9\u0440\u0441\u0435\u043d\u0431\u0456_\u0431\u0435\u0439\u0441\u0435\u043d\u0431\u0456_\u0436\u04b1\u043c\u0430_\u0441\u0435\u043d\u0431\u0456".split("_"),weekdaysShort:"\u0436\u0435\u043a_\u0434\u04af\u0439_\u0441\u0435\u0439_\u0441\u04d9\u0440_\u0431\u0435\u0439_\u0436\u04b1\u043c_\u0441\u0435\u043d".split("_"),weekdaysMin:"\u0436\u043a_\u0434\u0439_\u0441\u0439_\u0441\u0440_\u0431\u0439_\u0436\u043c_\u0441\u043d".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[\u0411\u04af\u0433\u0456\u043d \u0441\u0430\u0493\u0430\u0442] LT",nextDay:"[\u0415\u0440\u0442\u0435\u04a3 \u0441\u0430\u0493\u0430\u0442] LT",nextWeek:"dddd [\u0441\u0430\u0493\u0430\u0442] LT",lastDay:"[\u041a\u0435\u0448\u0435 \u0441\u0430\u0493\u0430\u0442] LT",lastWeek:"[\u04e8\u0442\u043a\u0435\u043d \u0430\u043f\u0442\u0430\u043d\u044b\u04a3] dddd [\u0441\u0430\u0493\u0430\u0442] LT",sameElse:"L"},relativeTime:{future:"%s \u0456\u0448\u0456\u043d\u0434\u0435",past:"%s \u0431\u04b1\u0440\u044b\u043d",s:"\u0431\u0456\u0440\u043d\u0435\u0448\u0435 \u0441\u0435\u043a\u0443\u043d\u0434",ss:"%d \u0441\u0435\u043a\u0443\u043d\u0434",m:"\u0431\u0456\u0440 \u043c\u0438\u043d\u0443\u0442",mm:"%d \u043c\u0438\u043d\u0443\u0442",h:"\u0431\u0456\u0440 \u0441\u0430\u0493\u0430\u0442",hh:"%d \u0441\u0430\u0493\u0430\u0442",d:"\u0431\u0456\u0440 \u043a\u04af\u043d",dd:"%d \u043a\u04af\u043d",M:"\u0431\u0456\u0440 \u0430\u0439",MM:"%d \u0430\u0439",y:"\u0431\u0456\u0440 \u0436\u044b\u043b",yy:"%d \u0436\u044b\u043b"},dayOfMonthOrdinalParse:/\d{1,2}-(\u0448\u0456|\u0448\u044b)/,ordinal:function(e){return e+(t[e]||t[e%10]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(n("wd/R"))},bYM6:function(e,t,n){!function(e){"use strict";e.defineLocale("ar-tn",{months:"\u062c\u0627\u0646\u0641\u064a_\u0641\u064a\u0641\u0631\u064a_\u0645\u0627\u0631\u0633_\u0623\u0641\u0631\u064a\u0644_\u0645\u0627\u064a_\u062c\u0648\u0627\u0646_\u062c\u0648\u064a\u0644\u064a\u0629_\u0623\u0648\u062a_\u0633\u0628\u062a\u0645\u0628\u0631_\u0623\u0643\u062a\u0648\u0628\u0631_\u0646\u0648\u0641\u0645\u0628\u0631_\u062f\u064a\u0633\u0645\u0628\u0631".split("_"),monthsShort:"\u062c\u0627\u0646\u0641\u064a_\u0641\u064a\u0641\u0631\u064a_\u0645\u0627\u0631\u0633_\u0623\u0641\u0631\u064a\u0644_\u0645\u0627\u064a_\u062c\u0648\u0627\u0646_\u062c\u0648\u064a\u0644\u064a\u0629_\u0623\u0648\u062a_\u0633\u0628\u062a\u0645\u0628\u0631_\u0623\u0643\u062a\u0648\u0628\u0631_\u0646\u0648\u0641\u0645\u0628\u0631_\u062f\u064a\u0633\u0645\u0628\u0631".split("_"),weekdays:"\u0627\u0644\u0623\u062d\u062f_\u0627\u0644\u0625\u062b\u0646\u064a\u0646_\u0627\u0644\u062b\u0644\u0627\u062b\u0627\u0621_\u0627\u0644\u0623\u0631\u0628\u0639\u0627\u0621_\u0627\u0644\u062e\u0645\u064a\u0633_\u0627\u0644\u062c\u0645\u0639\u0629_\u0627\u0644\u0633\u0628\u062a".split("_"),weekdaysShort:"\u0623\u062d\u062f_\u0625\u062b\u0646\u064a\u0646_\u062b\u0644\u0627\u062b\u0627\u0621_\u0623\u0631\u0628\u0639\u0627\u0621_\u062e\u0645\u064a\u0633_\u062c\u0645\u0639\u0629_\u0633\u0628\u062a".split("_"),weekdaysMin:"\u062d_\u0646_\u062b_\u0631_\u062e_\u062c_\u0633".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[\u0627\u0644\u064a\u0648\u0645 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextDay:"[\u063a\u062f\u0627 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",nextWeek:"dddd [\u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastDay:"[\u0623\u0645\u0633 \u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",lastWeek:"dddd [\u0639\u0644\u0649 \u0627\u0644\u0633\u0627\u0639\u0629] LT",sameElse:"L"},relativeTime:{future:"\u0641\u064a %s",past:"\u0645\u0646\u0630 %s",s:"\u062b\u0648\u0627\u0646",ss:"%d \u062b\u0627\u0646\u064a\u0629",m:"\u062f\u0642\u064a\u0642\u0629",mm:"%d \u062f\u0642\u0627\u0626\u0642",h:"\u0633\u0627\u0639\u0629",hh:"%d \u0633\u0627\u0639\u0627\u062a",d:"\u064a\u0648\u0645",dd:"%d \u0623\u064a\u0627\u0645",M:"\u0634\u0647\u0631",MM:"%d \u0623\u0634\u0647\u0631",y:"\u0633\u0646\u0629",yy:"%d \u0633\u0646\u0648\u0627\u062a"},week:{dow:1,doy:4}})}(n("wd/R"))},bpih:function(e,t,n){!function(e){"use strict";e.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_luned\xec_marted\xec_mercoled\xec_gioved\xec_venerd\xec_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:function(){return"[Oggi a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextDay:function(){return"[Domani a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextWeek:function(){return"dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastDay:function(){return"[Ieri a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastWeek:function(){switch(this.day()){case 0:return"[La scorsa] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT";default:return"[Lo scorso] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"}},sameElse:"L"},relativeTime:{future:"tra %s",past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",w:"una settimana",ww:"%d settimane",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:1,doy:4}})}(n("wd/R"))},busE:function(e,t,n){var i=n("2oRo"),r=n("kRJp"),s=n("UTVS"),o=n("zk60"),a=n("iSVu"),c=n("afO8"),l=c.get,u=c.enforce,d=String(String).split("String");(e.exports=function(e,t,n,a){var c,l=!!a&&!!a.unsafe,h=!!a&&!!a.enumerable,f=!!a&&!!a.noTargetGet;"function"==typeof n&&("string"!=typeof t||s(n,"name")||r(n,"name",t),(c=u(n)).source||(c.source=d.join("string"==typeof t?t:""))),e!==i?(l?!f&&e[t]&&(h=!0):delete e[t],h?e[t]=n:r(e,t,n)):h?e[t]=n:o(t,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&l(this).source||a(this)}))},bxKX:function(e,t,n){!function(e){"use strict";e.defineLocale("it-ch",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_luned\xec_marted\xec_mercoled\xec_gioved\xec_venerd\xec_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){switch(this.day()){case 0:return"[la scorsa] dddd [alle] LT";default:return"[lo scorso] dddd [alle] LT"}},sameElse:"L"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?"tra":"in")+" "+e},past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}\xba/,ordinal:"%d\xba",week:{dow:1,doy:4}})}(n("wd/R"))},c2HN:function(e,t,n){"use strict";function i(e){return!!e&&"function"!=typeof e.subscribe&&"function"==typeof e.then}n.d(t,"a",(function(){return i}))},cEzo:function(e,t,n){"use strict";n.d(t,"a",(function(){return u}));var i=n("e0ae"),r=n("oxzT"),s=n("8Y7J"),o=n("EApP"),a=n("ANnk"),c=n("SVse");const l=function(e){return[e]};let u=(()=>{class e{constructor(e){this.toastr=e,this.byId=!0,this.icons=r.a}getText(){return document.getElementById(this.source).value}onClick(){try{const e=Object(i.a)(),t=this.byId?this.getText():this.source,n=()=>{this.toastr.success("Copied text to the clipboard successfully.")};["firefox","ie","ios","safari"].includes(e.name)?navigator.clipboard.writeText(t).then(()=>n()):navigator.permissions.query({name:"clipboard-write"}).then(e=>{"granted"!==e.state&&"prompt"!==e.state||navigator.clipboard.writeText(t).then(()=>n())})}catch(e){this.toastr.error("Failed to copy text to the clipboard.")}}}return e.\u0275fac=function(t){return new(t||e)(s.Mb(o.b))},e.\u0275cmp=s.Gb({type:e,selectors:[["cd-copy-2-clipboard-button"]],hostBindings:function(e,t){1&e&&s.gc("click",(function(){return t.onClick()}))},inputs:{source:"source",byId:"byId"},decls:3,vars:3,consts:function(){return[["type","button",1,"btn","btn-light",3,"click",6,"title"],["title","Copy to Clipboard"],[3,"ngClass"]]},template:function(e,t){1&e&&(s.Sb(0,"button",0),s.Yb(1,1),s.gc("click",(function(){return t.onClick()})),s.Nb(2,"i",2),s.Rb()),2&e&&(s.yb(2),s.pc("ngClass",s.uc(1,l,t.icons.clipboard)))},directives:[a.a,c.p],styles:[""]}),e})()},cRix:function(e,t,n){!function(e){"use strict";var t="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),n="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");e.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(e,i){return e?/-MMM-/.test(i)?n[e.month()]:t[e.month()]:t},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[\xf4fr\xfbne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",ss:"%d sekonden",m:"ien min\xfat",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(n("wd/R"))},cSlR:function(e,t,n){"use strict";var i=/^(?:0|[1-9]\d*)$/;t.a=function(e,t){var n=typeof e;return!!(t=null==t?9007199254740991:t)&&("number"==n||"symbol"!=n&&i.test(e))&&e>-1&&e%1==0&&e{e.removeEventListener(t,n,!1)}}dispatchEvent(e,t){e.dispatchEvent(t)}remove(e){return e.parentNode&&e.parentNode.removeChild(e),e}getValue(e){return e.value}createElement(e,t){return(t=t||this.getDefaultDocument()).createElement(e)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}isShadowRoot(e){return e instanceof DocumentFragment}getGlobalEventTarget(e,t){return"window"===t?window:"document"===t?e:"body"===t?e.body:null}getHistory(){return window.history}getLocation(){return window.location}getBaseHref(e){const t=c||(c=document.querySelector("base"),c)?c.getAttribute("href"):null;return null==t?null:(n=t,a||(a=document.createElement("a")),a.setAttribute("href",n),"/"===a.pathname.charAt(0)?a.pathname:"/"+a.pathname);var n}resetBaseElement(){c=null}getUserAgent(){return window.navigator.userAgent}performanceNow(){return window.performance&&window.performance.now?window.performance.now():(new Date).getTime()}supportsCookies(){return!0}getCookie(e){return Object(i.M)(document.cookie,e)}}let a,c=null;const l=new r.r("TRANSITION_ID"),u=[{provide:r.d,useFactory:function(e,t,n){return()=>{n.get(r.e).donePromise.then(()=>{const n=Object(i.L)();Array.prototype.slice.apply(t.querySelectorAll("style[ng-transition]")).filter(t=>t.getAttribute("ng-transition")===e).forEach(e=>n.remove(e))})}},deps:[l,i.d,r.s],multi:!0}];class d{static init(){Object(r.W)(new d)}addToWindow(e){r.nb.getAngularTestability=(t,n=!0)=>{const i=e.findTestabilityInTree(t,n);if(null==i)throw new Error("Could not find testability for element.");return i},r.nb.getAllAngularTestabilities=()=>e.getAllTestabilities(),r.nb.getAllAngularRootElements=()=>e.getAllRootElements(),r.nb.frameworkStabilizers||(r.nb.frameworkStabilizers=[]),r.nb.frameworkStabilizers.push(e=>{const t=r.nb.getAllAngularTestabilities();let n=t.length,i=!1;const s=function(t){i=i||t,n--,0==n&&e(i)};t.forEach((function(e){e.whenStable(s)}))})}findTestabilityInTree(e,t,n){if(null==t)return null;const r=e.getTestability(t);return null!=r?r:n?Object(i.L)().isShadowRoot(t)?this.findTestabilityInTree(e,t.host,!0):this.findTestabilityInTree(e,t.parentElement,!0):null}}const h=new r.r("EventManagerPlugins");let f=(()=>{class e{constructor(e,t){this._zone=t,this._eventNameToPlugin=new Map,e.forEach(e=>e.manager=this),this._plugins=e.slice().reverse()}addEventListener(e,t,n){return this._findPluginFor(t).addEventListener(e,t,n)}addGlobalEventListener(e,t,n){return this._findPluginFor(t).addGlobalEventListener(e,t,n)}getZone(){return this._zone}_findPluginFor(e){const t=this._eventNameToPlugin.get(e);if(t)return t;const n=this._plugins;for(let i=0;i{class e{constructor(){this._stylesSet=new Set}addStyles(e){const t=new Set;e.forEach(e=>{this._stylesSet.has(e)||(this._stylesSet.add(e),t.add(e))}),this.onStylesAdded(t)}onStylesAdded(e){}getAllStyles(){return Array.from(this._stylesSet)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac}),e})(),b=(()=>{class e extends m{constructor(e){super(),this._doc=e,this._hostNodes=new Set,this._styleNodes=new Set,this._hostNodes.add(e.head)}_addStylesToHost(e,t){e.forEach(e=>{const n=this._doc.createElement("style");n.textContent=e,this._styleNodes.add(t.appendChild(n))})}addHost(e){this._addStylesToHost(this._stylesSet,e),this._hostNodes.add(e)}removeHost(e){this._hostNodes.delete(e)}onStylesAdded(e){this._hostNodes.forEach(t=>this._addStylesToHost(e,t))}ngOnDestroy(){this._styleNodes.forEach(e=>Object(i.L)().remove(e))}}return e.\u0275fac=function(t){return new(t||e)(r.dc(i.d))},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac}),e})();const g={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"},_=/%COMP%/g;function y(e,t,n){for(let i=0;i{if("__ngUnwrap__"===t)return e;!1===e(t)&&(t.preventDefault(),t.returnValue=!1)}}let w=(()=>{class e{constructor(e,t,n){this.eventManager=e,this.sharedStylesHost=t,this.appId=n,this.rendererByCompId=new Map,this.defaultRenderer=new S(e)}createRenderer(e,t){if(!e||!t)return this.defaultRenderer;switch(t.encapsulation){case r.Q.Emulated:{let n=this.rendererByCompId.get(t.id);return n||(n=new M(this.eventManager,this.sharedStylesHost,t,this.appId),this.rendererByCompId.set(t.id,n)),n.applyToHost(e),n}case r.Q.Native:case r.Q.ShadowDom:return new x(this.eventManager,this.sharedStylesHost,e,t);default:if(!this.rendererByCompId.has(t.id)){const e=y(t.id,t.styles,[]);this.sharedStylesHost.addStyles(e),this.rendererByCompId.set(t.id,this.defaultRenderer)}return this.defaultRenderer}}begin(){}end(){}}return e.\u0275fac=function(t){return new(t||e)(r.dc(f),r.dc(b),r.dc(r.c))},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac}),e})();class S{constructor(e){this.eventManager=e,this.data=Object.create(null)}destroy(){}createElement(e,t){return t?document.createElementNS(g[t]||t,e):document.createElement(e)}createComment(e){return document.createComment(e)}createText(e){return document.createTextNode(e)}appendChild(e,t){e.appendChild(t)}insertBefore(e,t,n){e&&e.insertBefore(t,n)}removeChild(e,t){e&&e.removeChild(t)}selectRootElement(e,t){let n="string"==typeof e?document.querySelector(e):e;if(!n)throw new Error(`The selector "${e}" did not match any elements`);return t||(n.textContent=""),n}parentNode(e){return e.parentNode}nextSibling(e){return e.nextSibling}setAttribute(e,t,n,i){if(i){t=i+":"+t;const r=g[i];r?e.setAttributeNS(r,t,n):e.setAttribute(t,n)}else e.setAttribute(t,n)}removeAttribute(e,t,n){if(n){const i=g[n];i?e.removeAttributeNS(i,t):e.removeAttribute(`${n}:${t}`)}else e.removeAttribute(t)}addClass(e,t){e.classList.add(t)}removeClass(e,t){e.classList.remove(t)}setStyle(e,t,n,i){i&r.G.DashCase?e.style.setProperty(t,n,i&r.G.Important?"important":""):e.style[t]=n}removeStyle(e,t,n){n&r.G.DashCase?e.style.removeProperty(t):e.style[t]=""}setProperty(e,t,n){e[t]=n}setValue(e,t){e.nodeValue=t}listen(e,t,n){return"string"==typeof e?this.eventManager.addGlobalEventListener(e,t,v(n)):this.eventManager.addEventListener(e,t,v(n))}}class M extends S{constructor(e,t,n,i){super(e),this.component=n;const r=y(i+"-"+n.id,n.styles,[]);t.addStyles(r),this.contentAttr="_ngcontent-%COMP%".replace(_,i+"-"+n.id),this.hostAttr="_nghost-%COMP%".replace(_,i+"-"+n.id)}applyToHost(e){super.setAttribute(e,this.hostAttr,"")}createElement(e,t){const n=super.createElement(e,t);return super.setAttribute(n,this.contentAttr,""),n}}class x extends S{constructor(e,t,n,i){super(e),this.sharedStylesHost=t,this.hostEl=n,this.component=i,this.shadowRoot=i.encapsulation===r.Q.ShadowDom?n.attachShadow({mode:"open"}):n.createShadowRoot(),this.sharedStylesHost.addHost(this.shadowRoot);const s=y(i.id,i.styles,[]);for(let r=0;r{class e extends p{constructor(e){super(e)}supports(e){return!0}addEventListener(e,t,n){return e.addEventListener(t,n,!1),()=>this.removeEventListener(e,t,n)}removeEventListener(e,t,n){return e.removeEventListener(t,n)}}return e.\u0275fac=function(t){return new(t||e)(r.dc(i.d))},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac}),e})();const D=["alt","control","meta","shift"],T={"\b":"Backspace","\t":"Tab","\x7f":"Delete","\x1b":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},C={A:"1",B:"2",C:"3",D:"4",E:"5",F:"6",G:"7",H:"8",I:"9",J:"*",K:"+",M:"-",N:".",O:"/","`":"0","\x90":"NumLock"},O={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey};let L=(()=>{class e extends p{constructor(e){super(e)}supports(t){return null!=e.parseEventName(t)}addEventListener(t,n,r){const s=e.parseEventName(n),o=e.eventCallback(s.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>Object(i.L)().onAndCancel(t,s.domEventName,o))}static parseEventName(t){const n=t.toLowerCase().split("."),i=n.shift();if(0===n.length||"keydown"!==i&&"keyup"!==i)return null;const r=e._normalizeKey(n.pop());let s="";if(D.forEach(e=>{const t=n.indexOf(e);t>-1&&(n.splice(t,1),s+=e+".")}),s+=r,0!=n.length||0===r.length)return null;const o={};return o.domEventName=i,o.fullKey=s,o}static getEventFullKey(e){let t="",n=function(e){let t=e.key;if(null==t){if(t=e.keyIdentifier,null==t)return"Unidentified";t.startsWith("U+")&&(t=String.fromCharCode(parseInt(t.substring(2),16)),3===e.location&&C.hasOwnProperty(t)&&(t=C[t]))}return T[t]||t}(e);return n=n.toLowerCase()," "===n?n="space":"."===n&&(n="dot"),D.forEach(i=>{i!=n&&(0,O[i])(e)&&(t+=i+".")}),t+=n,t}static eventCallback(t,n,i){return r=>{e.getEventFullKey(r)===t&&i.runGuarded(()=>n(r))}}static _normalizeKey(e){switch(e){case"esc":return"escape";default:return e}}}return e.\u0275fac=function(t){return new(t||e)(r.dc(i.d))},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac}),e})(),R=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=Object(r.Ib)({factory:function(){return Object(r.dc)(A)},token:e,providedIn:"root"}),e})();function E(e){return new A(e.get(i.d))}let A=(()=>{class e extends R{constructor(e){super(),this._doc=e}sanitize(e,t){if(null==t)return null;switch(e){case r.I.NONE:return t;case r.I.HTML:return Object(r.cb)(t,"HTML")?Object(r.ub)(t):Object(r.ab)(this._doc,String(t));case r.I.STYLE:return Object(r.cb)(t,"Style")?Object(r.ub)(t):t;case r.I.SCRIPT:if(Object(r.cb)(t,"Script"))return Object(r.ub)(t);throw new Error("unsafe value used in a script context");case r.I.URL:return Object(r.mb)(t),Object(r.cb)(t,"URL")?Object(r.ub)(t):Object(r.bb)(String(t));case r.I.RESOURCE_URL:if(Object(r.cb)(t,"ResourceURL"))return Object(r.ub)(t);throw new Error("unsafe value used in a resource URL context (see http://g.co/ng/security#xss)");default:throw new Error(`Unexpected SecurityContext ${e} (see http://g.co/ng/security#xss)`)}}bypassSecurityTrustHtml(e){return Object(r.db)(e)}bypassSecurityTrustStyle(e){return Object(r.gb)(e)}bypassSecurityTrustScript(e){return Object(r.fb)(e)}bypassSecurityTrustUrl(e){return Object(r.hb)(e)}bypassSecurityTrustResourceUrl(e){return Object(r.eb)(e)}}return e.\u0275fac=function(t){return new(t||e)(r.dc(i.d))},e.\u0275prov=Object(r.Ib)({factory:function(){return E(Object(r.dc)(r.p))},token:e,providedIn:"root"}),e})();const I=[{provide:r.C,useValue:i.K},{provide:r.D,useValue:function(){o.makeCurrent(),d.init()},multi:!0},{provide:i.d,useFactory:function(){return Object(r.sb)(document),document},deps:[]}],P=Object(r.R)(r.V,"browser",I),j=[[],{provide:r.Y,useValue:"root"},{provide:r.n,useFactory:function(){return new r.n},deps:[]},{provide:h,useClass:k,multi:!0,deps:[i.d,r.A,r.C]},{provide:h,useClass:L,multi:!0,deps:[i.d]},[],{provide:w,useClass:w,deps:[f,b,r.c]},{provide:r.F,useExisting:w},{provide:m,useExisting:b},{provide:b,useClass:b,deps:[i.d]},{provide:r.M,useClass:r.M,deps:[r.A]},{provide:f,useClass:f,deps:[h,r.A]},[]];let N=(()=>{class e{constructor(e){if(e)throw new Error("BrowserModule has already been loaded. If you need access to common directives such as NgIf and NgFor from a lazy loaded module, import CommonModule instead.")}static withServerTransition(t){return{ngModule:e,providers:[{provide:r.c,useValue:t.appId},{provide:l,useExisting:r.c},u]}}}return e.\u0275mod=r.Kb({type:e}),e.\u0275inj=r.Jb({factory:function(t){return new(t||e)(r.dc(e,12))},providers:j,imports:[i.c,r.f]}),e})();const F="undefined"!=typeof window&&window||{};class Y{constructor(e,t){this.msPerTick=e,this.numTicks=t}}class z{constructor(e){this.appRef=e.injector.get(r.g)}timeChangeDetection(e){const t=e&&e.record,n="Change Detection",r=null!=F.console.profile;t&&r&&F.console.profile(n);const s=Object(i.L)().performanceNow();let o=0;for(;o<5||Object(i.L)().performanceNow()-s<500;)this.appRef.tick(),o++;const a=Object(i.L)().performanceNow();t&&r&&F.console.profileEnd(n);const c=(a-s)/o;return F.console.log(`ran ${o} change detection cycles`),F.console.log(c.toFixed(2)+" ms per check"),new Y(c,o)}}function $(e){return"profiler",t=new z(e),"undefined"!=typeof COMPILED&&COMPILED||((r.nb.ng=r.nb.ng||{}).profiler=t),e;var t}},cVYH:function(e,t,n){var i=n("hh1v"),r=n("0rvr");e.exports=function(e,t,n){var s,o;return r&&"function"==typeof(s=t.constructor)&&s!==n&&i(o=s.prototype)&&o!==n.prototype&&r(e,o),e}},cp0P:function(e,t,n){"use strict";n.d(t,"a",(function(){return c}));var i=n("HDdC"),r=n("DH7j"),s=n("lJxs"),o=n("XoHu"),a=n("Cfvw");function c(...e){if(1===e.length){const t=e[0];if(Object(r.a)(t))return l(t,null);if(Object(o.a)(t)&&Object.getPrototypeOf(t)===Object.prototype){const e=Object.keys(t);return l(e.map(e=>t[e]),e)}}if("function"==typeof e[e.length-1]){const t=e.pop();return l(e=1===e.length&&Object(r.a)(e[0])?e[0]:e,null).pipe(Object(s.a)(e=>t(...e)))}return l(e,null)}function l(e,t){return new i.a(n=>{const i=e.length;if(0===i)return void n.complete();const r=new Array(i);let s=0,o=0;for(let c=0;c{u||(u=!0,o++),r[c]=e},error:e=>n.error(e),complete:()=>{s++,s!==i&&u||(o===i&&n.next(t?t.reduce((e,t,n)=>(e[t]=r[n],e),{}):r),n.complete())}}))}})}},czMo:function(e,t,n){!function(e){"use strict";e.defineLocale("en-il",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}})}(n("wd/R"))},"d+Og":function(e,t,n){"use strict";n.d(t,"a",(function(){return c}));var i=n("LvDl"),r=n.n(i),s=n("kJI8");let o=(()=>{class e{constructor(e){if(this.type=e,!this.isValidType())throw new Error("Wrong placement group category type");this.setTypeStates()}isValidType(){return e.VALID_CATEGORIES.includes(this.type)}setTypeStates(){switch(this.type){case e.CATEGORY_CLEAN:this.states=["active","clean"];break;case e.CATEGORY_WORKING:this.states=["activating","backfill_wait","backfilling","creating","deep","degraded","forced_backfill","forced_recovery","peering","peered","recovering","recovery_wait","repair","scrubbing","snaptrim","snaptrim_wait"];break;case e.CATEGORY_WARNING:this.states=["backfill_toofull","backfill_unfound","down","incomplete","inconsistent","recovery_toofull","recovery_unfound","remapped","snaptrim_error","stale","undersized"];break;default:this.states=[]}}}return e.CATEGORY_CLEAN="clean",e.CATEGORY_WORKING="working",e.CATEGORY_WARNING="warning",e.CATEGORY_UNKNOWN="unknown",e.VALID_CATEGORIES=[e.CATEGORY_CLEAN,e.CATEGORY_WORKING,e.CATEGORY_WARNING,e.CATEGORY_UNKNOWN],e})();var a=n("8Y7J");let c=(()=>{class e{constructor(){this.categories=this.createCategories()}getAllTypes(){return o.VALID_CATEGORIES}getTypeByStates(e){const t=this.getPgStatesFromText(e);if(0===t.length)return o.CATEGORY_UNKNOWN;const n=r.a.zipObject(o.VALID_CATEGORIES,o.VALID_CATEGORIES.map(e=>r.a.intersection(this.categories[e].states,t).length));if(n[o.CATEGORY_WARNING]>0)return o.CATEGORY_WARNING;const i=n[o.CATEGORY_WORKING];return t.length>n[o.CATEGORY_CLEAN]+i?o.CATEGORY_UNKNOWN:i?o.CATEGORY_WORKING:o.CATEGORY_CLEAN}createCategories(){return r.a.zipObject(o.VALID_CATEGORIES,o.VALID_CATEGORIES.map(e=>new o(e)))}getPgStatesFromText(e){const t=e.replace(/[^a-z]+/g," ").trim().split(" ");return r.a.uniq(t)}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275prov=a.Ib({token:e,factory:e.\u0275fac,providedIn:s.a}),e})()},"dBg+":function(e,t){t.f=Object.getOwnPropertySymbols},dEH0:function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{transform(e){return e+" ms"}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=i.Lb({name:"milliseconds",type:e,pure:!0}),e})()},dLWn:function(e,t,n){"use strict";var i=Function.prototype.toString;t.a=function(e){if(null!=e){try{return i.call(e)}catch(t){}try{return e+""}catch(t){}}return""}},dNwA:function(e,t,n){!function(e){"use strict";e.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"hh:mm A",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",ss:"sekunde %d",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"siku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,doy:7}})}(n("wd/R"))},dgut:function(e,t,n){"use strict";n.d(t,"a",(function(){return u}));var i=n("NEZu"),r=n("Fgil"),s=n("8Y7J"),o=n("SVse"),a=n("hrfs");const c=["sparkCanvas"],l=["sparkTooltip"];let u=(()=>{class e{constructor(e){this.dimlessBinaryPipe=e,this.style={height:"30px",width:"100px"},this.colors=[{backgroundColor:"rgba(40,140,234,0.2)",borderColor:"rgba(40,140,234,1)",pointBackgroundColor:"rgba(40,140,234,1)",pointBorderColor:"#fff",pointHoverBackgroundColor:"#fff",pointHoverBorderColor:"rgba(40,140,234,0.8)"}],this.options={animation:{duration:0},responsive:!0,maintainAspectRatio:!1,legend:{display:!1},elements:{line:{borderWidth:1}},tooltips:{enabled:!1,mode:"index",intersect:!1,custom:void 0,callbacks:{label:e=>this.isBinary?this.dimlessBinaryPipe.transform(e.yLabel):e.yLabel,title:()=>""}},scales:{yAxes:[{display:!1}],xAxes:[{display:!1}]}},this.datasets=[{data:[]}],this.labels=[]}ngOnInit(){const e=new i.a(this.chartCanvasRef,this.chartTooltipRef,(e,t)=>t+e.caretX+"px",e=>e.caretY-e.height-e.yPadding-5+"px");e.customColors={backgroundColor:this.colors[0].pointBackgroundColor,borderColor:this.colors[0].pointBorderColor},this.options.tooltips.custom=t=>{e.customTooltips(t)}}ngOnChanges(e){this.datasets[0].data=e.data.currentValue,this.labels=[...Array(e.data.currentValue.length)]}}return e.\u0275fac=function(t){return new(t||e)(s.Mb(r.a))},e.\u0275cmp=s.Gb({type:e,selectors:[["cd-sparkline"]],viewQuery:function(e,t){var n;1&e&&(s.Jc(c,!0),s.Jc(l,!0)),2&e&&(s.zc(n=s.hc())&&(t.chartCanvasRef=n.first),s.zc(n=s.hc())&&(t.chartTooltipRef=n.first))},inputs:{data:"data",style:"style",isBinary:"isBinary"},features:[s.wb],decls:6,vars:6,consts:[[1,"chart-container",3,"ngStyle"],["baseChart","",3,"labels","datasets","options","colors","chartType"],["sparkCanvas",""],[1,"chartjs-tooltip"],["sparkTooltip",""]],template:function(e,t){1&e&&(s.Sb(0,"div",0),s.Nb(1,"canvas",1,2),s.Sb(3,"div",3,4),s.Nb(5,"table"),s.Rb(),s.Rb()),2&e&&(s.pc("ngStyle",t.style),s.yb(1),s.pc("labels",t.labels)("datasets",t.datasets)("options",t.options)("colors",t.colors)("chartType","line"))},directives:[o.s,a.a],styles:['.chart-container[_ngcontent-%COMP%]{cursor:pointer;margin:auto;overflow:visible;position:absolute}canvas[_ngcontent-%COMP%]{user-select:none}.chartjs-tooltip[_ngcontent-%COMP%]{background:rgba(0,0,0,.7);border-radius:3px;color:#fff;font-family:Helvetica Neue,Helvetica,Arial,sans-serif!important;opacity:0;pointer-events:none;position:absolute;transform:translate(-50%);transition:all .1s ease}.chartjs-tooltip.transform-left[_ngcontent-%COMP%]{transform:translate(-10%)}.chartjs-tooltip.transform-left[_ngcontent-%COMP%]:after{left:10%}.chartjs-tooltip.transform-right[_ngcontent-%COMP%]{transform:translate(-90%)}.chartjs-tooltip.transform-right[_ngcontent-%COMP%]:after{left:90%}.chartjs-tooltip[_ngcontent-%COMP%]:after{border:5px solid transparent;border-top-color:#000;content:" ";left:50%;margin-left:-5px;position:absolute;top:100%} .chartjs-tooltip-key{display:inline-block;height:10px;margin-right:10px;width:10px}.chart-container[_ngcontent-%COMP%]{position:static!important}']}),e})()},"e+ae":function(e,t,n){!function(e){"use strict";var t="janu\xe1r_febru\xe1r_marec_apr\xedl_m\xe1j_j\xfan_j\xfal_august_september_okt\xf3ber_november_december".split("_"),n="jan_feb_mar_apr_m\xe1j_j\xfan_j\xfal_aug_sep_okt_nov_dec".split("_");function i(e){return e>1&&e<5}function r(e,t,n,r){var s=e+" ";switch(n){case"s":return t||r?"p\xe1r sek\xfand":"p\xe1r sekundami";case"ss":return t||r?s+(i(e)?"sekundy":"sek\xfand"):s+"sekundami";case"m":return t?"min\xfata":r?"min\xfatu":"min\xfatou";case"mm":return t||r?s+(i(e)?"min\xfaty":"min\xfat"):s+"min\xfatami";case"h":return t?"hodina":r?"hodinu":"hodinou";case"hh":return t||r?s+(i(e)?"hodiny":"hod\xedn"):s+"hodinami";case"d":return t||r?"de\u0148":"d\u0148om";case"dd":return t||r?s+(i(e)?"dni":"dn\xed"):s+"d\u0148ami";case"M":return t||r?"mesiac":"mesiacom";case"MM":return t||r?s+(i(e)?"mesiace":"mesiacov"):s+"mesiacmi";case"y":return t||r?"rok":"rokom";case"yy":return t||r?s+(i(e)?"roky":"rokov"):s+"rokmi"}}e.defineLocale("sk",{months:t,monthsShort:n,weekdays:"nede\u013ea_pondelok_utorok_streda_\u0161tvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_\u0161t_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_\u0161t_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nede\u013eu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo \u0161tvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[v\u010dera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minul\xfa nede\u013eu o] LT";case 1:case 2:return"[minul\xfd] dddd [o] LT";case 3:return"[minul\xfa stredu o] LT";case 4:case 5:return"[minul\xfd] dddd [o] LT";case 6:return"[minul\xfa sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:r,ss:r,m:r,mm:r,h:r,hh:r,d:r,dd:r,M:r,MM:r,y:r,yy:r},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(n("wd/R"))},e0ae:function(e,t,n){"use strict";n.d(t,"a",(function(){return d}));var i=function(e,t,n){this.name=e,this.version=t,this.os=n,this.type="browser"},r=function(e){this.version=e,this.type="node",this.name="node",this.os=process.platform},s=function(e,t,n,i){this.name=e,this.version=t,this.os=n,this.bot=i,this.type="bot-device"},o=function(){this.type="bot",this.bot=!0,this.name="bot",this.version=null,this.os=null},a=function(){this.type="react-native",this.name="react-native",this.version=null,this.os=null},c=/(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask\ Jeeves\/Teoma|ia_archiver)/,l=[["aol",/AOLShield\/([0-9\._]+)/],["edge",/Edge\/([0-9\._]+)/],["edge-ios",/EdgiOS\/([0-9\._]+)/],["yandexbrowser",/YaBrowser\/([0-9\._]+)/],["kakaotalk",/KAKAOTALK\s([0-9\.]+)/],["samsung",/SamsungBrowser\/([0-9\.]+)/],["silk",/\bSilk\/([0-9._-]+)\b/],["miui",/MiuiBrowser\/([0-9\.]+)$/],["beaker",/BeakerBrowser\/([0-9\.]+)/],["edge-chromium",/EdgA?\/([0-9\.]+)/],["chromium-webview",/(?!Chrom.*OPR)wv\).*Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/],["chrome",/(?!Chrom.*OPR)Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/],["phantomjs",/PhantomJS\/([0-9\.]+)(:?\s|$)/],["crios",/CriOS\/([0-9\.]+)(:?\s|$)/],["firefox",/Firefox\/([0-9\.]+)(?:\s|$)/],["fxios",/FxiOS\/([0-9\.]+)/],["opera-mini",/Opera Mini.*Version\/([0-9\.]+)/],["opera",/Opera\/([0-9\.]+)(?:\s|$)/],["opera",/OPR\/([0-9\.]+)(:?\s|$)/],["ie",/Trident\/7\.0.*rv\:([0-9\.]+).*\).*Gecko$/],["ie",/MSIE\s([0-9\.]+);.*Trident\/[4-7].0/],["ie",/MSIE\s(7\.0)/],["bb10",/BB10;\sTouch.*Version\/([0-9\.]+)/],["android",/Android\s([0-9\.]+)/],["ios",/Version\/([0-9\._]+).*Mobile.*Safari.*/],["safari",/Version\/([0-9\._]+).*Safari/],["facebook",/FBAV\/([0-9\.]+)/],["instagram",/Instagram\s([0-9\.]+)/],["ios-webview",/AppleWebKit\/([0-9\.]+).*Mobile/],["ios-webview",/AppleWebKit\/([0-9\.]+).*Gecko\)$/],["searchbot",/alexa|bot|crawl(er|ing)|facebookexternalhit|feedburner|google web preview|nagios|postrank|pingdom|slurp|spider|yahoo!|yandex/]],u=[["iOS",/iP(hone|od|ad)/],["Android OS",/Android/],["BlackBerry OS",/BlackBerry|BB10/],["Windows Mobile",/IEMobile/],["Amazon OS",/Kindle/],["Windows 3.11",/Win16/],["Windows 95",/(Windows 95)|(Win95)|(Windows_95)/],["Windows 98",/(Windows 98)|(Win98)/],["Windows 2000",/(Windows NT 5.0)|(Windows 2000)/],["Windows XP",/(Windows NT 5.1)|(Windows XP)/],["Windows Server 2003",/(Windows NT 5.2)/],["Windows Vista",/(Windows NT 6.0)/],["Windows 7",/(Windows NT 6.1)/],["Windows 8",/(Windows NT 6.2)/],["Windows 8.1",/(Windows NT 6.3)/],["Windows 10",/(Windows NT 10.0)/],["Windows ME",/Windows ME/],["Open BSD",/OpenBSD/],["Sun OS",/SunOS/],["Chrome OS",/CrOS/],["Linux",/(Linux)|(X11)/],["Mac OS",/(Mac_PowerPC)|(Macintosh)/],["QNX",/QNX/],["BeOS",/BeOS/],["OS/2",/OS\/2/]];function d(e){return e?h(e):"undefined"==typeof document&&"undefined"!=typeof navigator&&"ReactNative"===navigator.product?new a:"undefined"!=typeof navigator?h(navigator.userAgent):"undefined"!=typeof process&&process.version?new r(process.version.slice(1)):null}function h(e){var t=function(e){return""!==e&&l.reduce((function(t,n){var i=n[0];if(t)return t;var r=n[1].exec(e);return!!r&&[i,r]}),!1)}(e);if(!t)return null;var n=t[0],r=t[1];if("searchbot"===n)return new o;var a=r[1]&&r[1].split(/[._]/).slice(0,3);a?a.length<3&&(a=function(){for(var e=0,t=0,n=arguments.length;tn.pipe(o((n,s)=>Object(r.a)(e(n,s)).pipe(Object(i.a)((e,i)=>t(n,e,s,i))))):t=>t.lift(new a(e))}class a{constructor(e){this.project=e}call(e,t){return t.subscribe(new c(e,this.project))}}class c extends s.b{constructor(e,t){super(e),this.project=t,this.index=0}_next(e){let t;const n=this.index++;try{t=this.project(e,n)}catch(i){return void this.destination.error(i)}this._innerSub(t)}_innerSub(e){const t=this.innerSubscription;t&&t.unsubscribe();const n=new s.a(this),i=this.destination;i.add(n),this.innerSubscription=Object(s.c)(e,n),this.innerSubscription!==n&&i.add(this.innerSubscription)}_complete(){const{innerSubscription:e}=this;e&&!e.closed||super._complete(),this.unsubscribe()}_unsubscribe(){this.innerSubscription=void 0}notifyComplete(){this.innerSubscription=void 0,this.isStopped&&super._complete()}notifyNext(e){this.destination.next(e)}}},efK2:function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("LvDl"),r=n.n(i),s=n("8Y7J");let o=(()=>{class e{transform(e,t,n){return r.a.isString(e)?(n=r.a.defaultTo(n,""),r.a.truncate(e,{length:t,omission:n})):e}}return e.\u0275fac=function(t){return new(t||e)},e.\u0275pipe=s.Lb({name:"truncate",type:e,pure:!0}),e})()},"ej+x":function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var i=n("lOp/"),r=n("8Y7J"),s=n("IheW");let o=(()=>{class e{constructor(e,t){this.http=e,this.timerService=t,this.API_URL="api/feature_toggles",this.REFRESH_INTERVAL=3e4,this.featureToggleMap$=this.timerService.get(()=>this.http.get(this.API_URL),this.REFRESH_INTERVAL)}get(){return this.featureToggleMap$}}return e.\u0275fac=function(t){return new(t||e)(r.dc(s.b),r.dc(i.a))},e.\u0275prov=r.Ib({token:e,factory:e.\u0275fac,providedIn:"root"}),e})()},ewvW:function(e,t,n){var i=n("HYAF");e.exports=function(e){return Object(i(e))}},"f/UV":function(e,t,n){"use strict";n.d(t,"a",(function(){return r}));var i=n("8Y7J");let r=(()=>{class e{}return e.\u0275fac=function(t){return new(t||e)},e.\u0275dir=i.Hb({type:e,selectors:[["","cdFormScope",""]],inputs:{cdFormScope:"cdFormScope"}}),e})()},f5p1:function(e,t,n){var i=n("2oRo"),r=n("iSVu"),s=i.WeakMap;e.exports="function"==typeof s&&/native code/.test(r(s))},f69J:function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var i=n("8Y7J"),r=n("s7LF");let s=(()=>{class e{constructor(e){this.parent=e}get validClass(){return!!this.control&&this.control.valid&&(this.control.touched||this.control.dirty)}get invalidClass(){return!!this.control&&this.control.invalid&&this.control.touched&&this.control.dirty}get path(){return[...this.parent.path,this.formControlName]}get control(){return this.formDirective&&this.formDirective.getControl(this)}get formDirective(){return this.parent?this.parent.formDirective:null}}return e.\u0275fac=function(t){return new(t||e)(i.Mb(r.c,13))},e.\u0275dir=i.Hb({type:e,selectors:[["",8,"form-control"],["",8,"form-check-input"],["",8,"custom-control-input"]],hostVars:4,hostBindings:function(e,t){2&e&&i.Eb("is-valid",t.validClass)("is-invalid",t.invalidClass)},inputs:{formControlName:"formControlName",formControl:"formControl"}}),e})()},fHMY:function(e,t,n){var i,r=n("glrk"),s=n("N+g0"),o=n("eDl+"),a=n("0BK2"),c=n("G+Rx"),l=n("zBJ4"),u=n("93I0")("IE_PROTO"),d=function(){},h=function(e){return"