diff --git a/BUILD.md b/BUILD.md index c8d4785d08..db81ecb30d 100644 --- a/BUILD.md +++ b/BUILD.md @@ -21,8 +21,8 @@ These dependencies need not be installed manually. They are automatically downloaded on the platforms where they are required. - [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases): 2.83 - [glm](https://glm.g-truc.net/0.9.8/index.html): 0.9.8 -- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Win32) / 0.5 (Mac) -- [OpenVR](https://github.com/ValveSoftware/openvr): 1.11.11 (Win32 only) +- [Oculus SDK](https://developer.oculus.com/downloads/): 1.11 (Windows) / 0.5 (Mac) +- [OpenVR](https://github.com/ValveSoftware/openvr): 1.11.11 (Windows, Linux) - [Polyvox](http://www.volumesoffun.com/): 0.2.1 - [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/): 0.7.3 - [SDL2](https://www.libsdl.org/download-2.0.php): 2.0.3 diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index f88e7173c8..f6287846ed 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -1,6 +1,6 @@ # Build Linux -*Last Updated on January 20, 2020* +*Last Updated on April 11, 2020* Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file. diff --git a/BUILD_OSX.md b/BUILD_OSX.md index b39aadb287..2f9246f6a6 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -1,6 +1,6 @@ # Build OSX -*Last Updated on April 30, 2019* +*Last Updated on July 13, 2020* Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only macOS specific instructions are found in this document. @@ -8,24 +8,29 @@ Please read the [general build guide](BUILD.md) for information on dependencies [Homebrew](https://brew.sh/) is an excellent package manager for macOS. It makes install of some Vircadia dependencies very simple. - brew install cmake openssl + brew install cmake openssl npm ### Python 3 Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/). Execute the `Update Shell Profile.command` script that is provided with the installer. +### OSX SDK + +You will need the OSX SDK for building. The easiest way to get this is to install Xcode from the App Store. + ### OpenSSL Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations. -For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR: +For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR via + `export OPENSSL_ROOT_DIR=/usr/local/opt/openssl` + or by appending `-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl` to `cmake` - export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2l - -Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change. ### Xcode -If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. +If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. You will need to select the Xcode installation in the terminal first if you have not done so already. + + sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer cmake .. -G Xcode @@ -34,3 +39,7 @@ If `cmake` complains about Python 3 being missing, you may need to update your C After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run. If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories. + +### make + +If you build with make rather than Xcode, you can append `-j4`for assigning more threads. The number indicates the number of threads, e.g. 4. diff --git a/INSTALL.md b/INSTALL.md index bbaaafd6ef..af398ee6b3 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -9,7 +9,7 @@ This variable is set by the `project(hifi)` command in `CMakeLists.txt` to `C:/P ### Packaging -To produce an installer, run the `package` target. +To produce an installer, run the `package` target. However you will want to follow the steps specific to your platform below. #### Windows @@ -62,7 +62,6 @@ To produce an executable installer on Windows, the following are required: 1. Perform a clean cmake from a new terminal. 1. Open the `vircadia.sln` solution with elevated (administrator) permissions on Visual Studio and select the **Release** configuration. 1. Build the solution. -1. Build CMakeTargets->INSTALL 1. Build `packaged-server-console-npm-install` (found under **hidden/Server Console**) 1. Build `packaged-server-console` (found under **Server Console**) This will add 2 folders to `build\server-console\` - diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index ad68b07bb1..59e53bb2cb 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -615,6 +615,10 @@ void Agent::setIsAvatar(bool isAvatar) { delete _avatarQueryTimer; _avatarQueryTimer = nullptr; + // Clear the skeleton model so that if agent is set to an avatar again the skeleton model is (re)loaded. + auto scriptedAvatar = DependencyManager::get(); + scriptedAvatar->setSkeletonModelURL(QUrl()); + // The avatar mixer never times out a connection (e.g., based on identity or data packets) // but rather keeps avatars in its list as long as "connected". As a result, clients timeout // when we stop sending identity, but then get woken up again by the mixer itself, which sends diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 529ad4b387..cbf6ff4eaf 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -23,6 +23,7 @@ #include #include #include +#include ScriptableAvatar::ScriptableAvatar() { @@ -221,7 +222,7 @@ void ScriptableAvatar::updateJointMappings() { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); DependencyManager::get()->update( _skeletonModelURL, -1, "AvatarData::updateJointMappings"); QNetworkReply* networkReply = networkAccessManager.get(networkRequest); diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index a6ab382781..4c4fcbf2dd 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -370,16 +370,18 @@ void EntityServer::entityFilterAdded(EntityItemID id, bool success) { void EntityServer::nodeAdded(SharedNodePointer node) { EntityTreePointer tree = std::static_pointer_cast(_tree); - tree->knowAvatarID(node->getUUID()); + if (tree) { + tree->knowAvatarID(node->getUUID()); + } OctreeServer::nodeAdded(node); } void EntityServer::nodeKilled(SharedNodePointer node) { EntityTreePointer tree = std::static_pointer_cast(_tree); - tree->withWriteLock([&] { + if (tree) { tree->deleteDescendantsOfAvatar(node->getUUID()); - }); - tree->forgetAvatarID(node->getUUID()); + tree->forgetAvatarID(node->getUUID()); + } OctreeServer::nodeKilled(node); } diff --git a/cmake/ports/hifi-client-deps/CONTROL b/cmake/ports/hifi-client-deps/CONTROL index 7070cb6fb9..4a8a2bc44e 100644 --- a/cmake/ports/hifi-client-deps/CONTROL +++ b/cmake/ports/hifi-client-deps/CONTROL @@ -1,4 +1,4 @@ Source: hifi-client-deps Version: 0.1 Description: Collected dependencies for High Fidelity applications -Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr (windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator +Build-Depends: hifi-deps, aristo (windows), glslang, liblo (windows), nlohmann-json, openvr (linux|windows), quazip (!android), sdl2 (!android), spirv-cross (!android), spirv-tools (!android), sranipal (windows), vulkanmemoryallocator diff --git a/cmake/ports/openvr/portfile.cmake b/cmake/ports/openvr/portfile.cmake index b91bdd1d54..bcbac8613a 100644 --- a/cmake/ports/openvr/portfile.cmake +++ b/cmake/ports/openvr/portfile.cmake @@ -11,15 +11,23 @@ vcpkg_from_github( set(VCPKG_LIBRARY_LINKAGE dynamic) if(VCPKG_TARGET_ARCHITECTURE STREQUAL "x64") - set(ARCH_PATH "win64") + if(WIN32) + set(ARCH_PATH "win64") + else() + set(ARCH_PATH "linux64") + endif() elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "x86") - set(ARCH_PATH "win32") + if(WIN32) + set(ARCH_PATH "win32") + else() + set(ARCH_PATH "linux32") + endif() else() - message(FATAL_ERROR "Package only supports x64 and x86 windows.") + message(FATAL_ERROR "Package only supports x64 and x86 Windows and Linux.") endif() -if(VCPKG_CMAKE_SYSTEM_NAME) - message(FATAL_ERROR "Package only supports windows desktop.") +if(VCPKG_CMAKE_SYSTEM_NAME AND NOT (VCPKG_CMAKE_SYSTEM_NAME STREQUAL "Linux")) + message(FATAL_ERROR "Package only supports Windows or Linux desktop.") endif() file(MAKE_DIRECTORY @@ -28,18 +36,35 @@ file(MAKE_DIRECTORY ${CURRENT_PACKAGES_DIR}/debug/lib ${CURRENT_PACKAGES_DIR}/debug/bin ) -file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/lib) -file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) -file(COPY - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb - DESTINATION ${CURRENT_PACKAGES_DIR}/bin -) -file(COPY - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll - ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb - DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin -) + +if(WIN32) + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/lib) + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/openvr_api.lib DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb + DESTINATION ${CURRENT_PACKAGES_DIR}/bin + ) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.dll + ${SOURCE_PATH}/bin/${ARCH_PATH}/openvr_api.pdb + DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin + ) +else() + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/libopenvr_api.so DESTINATION ${CURRENT_PACKAGES_DIR}/lib) + file(COPY ${SOURCE_PATH}/lib/${ARCH_PATH}/libopenvr_api.so DESTINATION ${CURRENT_PACKAGES_DIR}/debug/lib) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so.dbg + DESTINATION ${CURRENT_PACKAGES_DIR}/bin + ) + file(COPY + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so + ${SOURCE_PATH}/bin/${ARCH_PATH}/libopenvr_api.so.dbg + DESTINATION ${CURRENT_PACKAGES_DIR}/debug/bin + ) +endif() + file(COPY ${SOURCE_PATH}/headers DESTINATION ${CURRENT_PACKAGES_DIR}) file(RENAME ${CURRENT_PACKAGES_DIR}/headers ${CURRENT_PACKAGES_DIR}/include) diff --git a/cmake/ports/sranipal/portfile.cmake b/cmake/ports/sranipal/portfile.cmake index 2e6acea361..4c4d88e567 100644 --- a/cmake/ports/sranipal/portfile.cmake +++ b/cmake/ports/sranipal/portfile.cmake @@ -7,9 +7,9 @@ file(READ "${VCPKG_ROOT_DIR}/_env/EXTERNAL_BUILD_ASSETS.txt" EXTERNAL_BUILD_ASSE if (WIN32) vcpkg_download_distfile( SRANIPAL_SOURCE_ARCHIVE - URLS "${EXTERNAL_BUILD_ASSETS}/seth/sranipal-1.1.0.1-windows.zip" - SHA512 b09ce012abe4e3c71e8e69626bdd7823ff6576601a821ab365275f2764406a3e5f7b65fcf2eb1d0962eff31eb5958a148b00901f67c229dc6ace56eb5e6c9e1b - FILENAME sranipal-1.1.0.1-windows.zip + URLS "${EXTERNAL_BUILD_ASSETS}/seth/sranipal-1.1.0.1-2-windows.zip" + SHA512 f1f68f6beef52ae5e034bc3f44932ae0800ee187b75d80e76ae7b17b8ddd7bc54c039ce5594d231035e3caf3a61fed36f38621a860b4fb20170cb0176d9c28f0 + FILENAME sranipal-1.1.0.1-2-windows.zip ) vcpkg_extract_source_archive(${SRANIPAL_SOURCE_ARCHIVE}) diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 8e621b8f2d..fe0d95e8b1 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -871,7 +871,7 @@ Function PostInstallOptionsPage Pop $LaunchConsoleNowCheckbox ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + !insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_UNCHECKED} ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE ${IfNot} $substringResult == "" ${NSD_SetState} $LaunchConsoleNowCheckbox ${BST_UNCHECKED} @@ -887,7 +887,7 @@ Function PostInstallOptionsPage IntOp $CurrentOffset $CurrentOffset + 15 ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} + !insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_UNCHECKED} ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)" Pop $CleanInstallCheckbox @@ -940,8 +940,8 @@ Function ReadInstallTypes StrCpy $Express "1" StrCpy $DesktopClientState ${BST_CHECKED} - StrCpy $ConsoleStartupState ${BST_CHECKED} - StrCpy $LaunchConsoleNowState ${BST_CHECKED} + StrCpy $ConsoleStartupState ${BST_UNCHECKED} + StrCpy $LaunchConsoleNowState ${BST_UNCHECKED} StrCpy $LaunchClientNowState ${BST_CHECKED} StrCpy $CleanInstallState ${BST_UNCHECKED} StrCpy $DesktopConsoleState ${BST_UNCHECKED} diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index be40611f14..9b3b716a4a 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -3,7 +3,7 @@ "settings": [ { "name": "metaverse", - "label": "Metaverse / Networking", + "label": "Networking / Metaverse", "settings": [ { "name": "access_token", @@ -73,6 +73,39 @@ } ] }, + { + "name": "authentication", + "label": "Networking / WordPress OAuth2", + "settings": [ + { + "name": "enable_oauth2", + "label": "Enable OAuth2 Authentication", + "help": "Allow a WordPress-based (miniOrange) OAuth2 service to assign users to groups based on their role with the service.", + "default": false, + "type": "checkbox", + "advanced": true + }, + { + "name": "oauth2_url_path", + "label": "Authentication URL", + "help": "The URL that the Interface will use to login via OAuth2.", + "advanced": true + }, + { + "name": "wordpress_url_base", + "label": "WordPress API URL Base", + "help": "The URL base that the domain server will use to make WordPress API calls. Typically \"https://oursite.com/wp-json/\". However, if using non-pretty permalinks or otherwise get a 404 error then try \"https://oursite.com/?rest_route=/\".", + "advanced": true + }, + { + "name": "plugin_client_id", + "label": "WordPress Plugin Client ID", + "help": "This is the client ID from the WordPress plugin configuration.", + "advanced": true, + "backup": false + } + ] + }, { "label": "Monitoring", "name": "monitoring", @@ -271,7 +304,7 @@ "name": "standard_permissions", "type": "table", "label": "Domain-Wide User Permissions", - "help": "Indicate which types of users can have which domain-wide permissions.", + "help": "Indicate which types of users can have which domain-wide permissions.", "caption": "Standard Permissions", "can_add_new_rows": false, "groups": [ @@ -280,7 +313,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -361,7 +394,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -405,6 +438,7 @@ "name": "group_permissions", "type": "table", "caption": "Permissions for Users in Groups", + "help": "For groups that are provided from WordPress you need to denote them by putting an \"@\" symbol in front of each item, e.g., \"@silver\".", "categorize_by_key": "permissions_id", "can_add_new_categories": true, "can_add_new_rows": false, @@ -416,7 +450,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -522,7 +556,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -533,6 +567,7 @@ "name": "group_forbiddens", "type": "table", "caption": "Permissions Denied to Users in Groups", + "help": "For groups that are provided from WordPress you need to denote them by putting an \"@\" symbol in front of each item, e.g., \"@silver\".", "categorize_by_key": "permissions_id", "can_add_new_categories": true, "can_add_new_rows": false, @@ -544,7 +579,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -647,7 +682,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -665,7 +700,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -746,7 +781,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -764,7 +799,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -845,7 +880,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -863,7 +898,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -944,7 +979,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false @@ -962,7 +997,7 @@ "span": 1 }, { - "label": "Permissions ?", + "label": "Permissions ?", "span": 11 } ], @@ -1043,7 +1078,7 @@ }, { "name": "id_can_get_and_set_private_user_data", - "label": "Can Get and Set Private User Data", + "label": "Get and Set Private User Data", "type": "checkbox", "editable": true, "default": false diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 09a0446468..ead4002334 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -4,6 +4,7 @@ // // Created by Stephen Birarda on 2015-08-24. // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -94,6 +95,9 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetBytesLeftToRead() > 0) { // read username from packet packetStream >> username; @@ -101,10 +105,25 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointergetBytesLeftToRead() > 0) { // read user signature from packet packetStream >> usernameSignature; + + if (message->getBytesLeftToRead() > 0) { + // Read domain username from packet. + packetStream >> domainUsername; + domainUsername = domainUsername.toLower(); // Domain usernames are case-insensitive; internally lower-case. + + if (message->getBytesLeftToRead() > 0) { + // Read domain tokens from packet. + + QString domainTokensString; + packetStream >> domainTokensString; + domainTokens = domainTokensString.split(":"); + } + } } } - node = processAgentConnectRequest(nodeConnection, username, usernameSignature); + node = processAgentConnectRequest(nodeConnection, username, usernameSignature, + domainUsername, domainTokens.value(0), domainTokens.value(1)); } if (node) { @@ -142,7 +161,8 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer_settingsManager.getDomainServerGroupNames() + .filter(QRegularExpression("^(.*[\\s,])?" + QRegularExpression::escape(userGroup) + "([\\s,].*)?$", + QRegularExpression::CaseInsensitiveOption)); + foreach(QString domainGroup, domainGroups) { + userPerms |= _server->_settingsManager.getPermissionsForGroup(domainGroup, QUuid()); // No rank for domain groups. +#ifdef WANT_DEBUG + qDebug() << "| user-permissions: domain user " << verifiedDomainUserName << "is in group:" << domainGroup + << "so:" << userPerms; +#endif + } + } + } + if (verifiedUsername.isEmpty()) { userPerms |= _server->_settingsManager.getStandardPermissionsForName(NodePermissions::standardNameAnonymous); #ifdef WANT_DEBUG @@ -256,6 +297,27 @@ NodePermissions DomainGatekeeper::setPermissionsForUser(bool isLocalUser, QStrin userPerms.setVerifiedUserName(verifiedUsername); } + // If this user is a known member of an domain group that is blacklisted, remove the implied permissions. + if (!verifiedDomainUserName.isEmpty()) { + auto userGroups = _domainGroupMemberships[verifiedDomainUserName]; + foreach(QString userGroup, userGroups) { + // A domain group is signified by a leading special character, "@". + // Multiple domain groups may be specified in one domain server setting as a comma- and/or space-separated lists of + // domain group names. For example, "@silver @Gold, @platinum". + auto domainGroups = _server->_settingsManager.getDomainServerBlacklistGroupNames() + .filter(QRegularExpression("^(.*[\\s,])?" + QRegularExpression::escape(userGroup) + "([\\s,].*)?$", + QRegularExpression::CaseInsensitiveOption)); + foreach(QString domainGroup, domainGroups) { + userPerms &= ~_server->_settingsManager.getForbiddensForGroup(domainGroup, QUuid()); +#ifdef WANT_DEBUG + qDebug() << "| user-permissions: domain user is in blacklist group:" << domainGroup << "so:" << userPerms; +#endif + } + } + + userPerms.setVerifiedDomainUserName(verifiedDomainUserName); + } + #ifdef WANT_DEBUG qDebug() << "| user-permissions: final:" << userPerms; #endif @@ -275,6 +337,7 @@ void DomainGatekeeper::updateNodePermissions() { // the id and the username in NodePermissions will often be the same, but id is set before // authentication and verifiedUsername is only set once they user's key has been confirmed. QString verifiedUsername = node->getPermissions().getVerifiedUserName(); + QString verifiedDomainUserName = node->getPermissions().getVerifiedDomainUserName(); NodePermissions userPerms(NodePermissionsKey(verifiedUsername, 0)); if (node->getPermissions().isAssignment) { @@ -309,7 +372,8 @@ void DomainGatekeeper::updateNodePermissions() { sendingAddress == QHostAddress::LocalHost); } - userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, connectingAddr.getAddress(), hardwareAddress, machineFingerprint); + userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, verifiedDomainUserName, + connectingAddr.getAddress(), hardwareAddress, machineFingerprint); } node->setPermissions(userPerms); @@ -387,12 +451,19 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo return newNode; } +const QString AUTHENTICATION_ENABLE_OAUTH2 = "authentication.enable_oauth2"; +const QString AUTHENTICATION_OAUTH2_URL_PATH = "authentication.oauth2_url_path"; +const QString AUTHENTICATION_WORDPRESS_URL_BASE = "authentication.wordpress_url_base"; +const QString AUTHENTICATION_PLUGIN_CLIENT_ID = "authentication.plugin_client_id"; const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity"; const QString MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION = "security.maximum_user_capacity_redirect_location"; SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnectionData& nodeConnection, const QString& username, - const QByteArray& usernameSignature) { + const QByteArray& usernameSignature, + const QString& domainUsername, + const QString& domainAccessToken, + const QString& domainRefreshToken) { auto limitedNodeList = DependencyManager::get(); @@ -419,7 +490,9 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect #ifdef WANT_DEBUG qDebug() << "stalling login because we have no username-signature:" << username; #endif - return SharedNodePointer(); + if (!domainHasLogin() || domainUsername.isEmpty()) { + return SharedNodePointer(); + } } else if (verifyUserSignature(username, usernameSignature, nodeConnection.senderSockAddr)) { // they sent us a username and the signature verifies it getGroupMemberships(username); @@ -430,16 +503,70 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect #ifdef WANT_DEBUG qDebug() << "stalling login because signature verification failed:" << username; #endif - return SharedNodePointer(); + if (!domainHasLogin() || domainUsername.isEmpty()) { + return SharedNodePointer(); + } } } - userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, nodeConnection.senderSockAddr.getAddress(), - nodeConnection.hardwareAddress, nodeConnection.machineFingerprint); + // The domain may have its own users and groups. + QString verifiedDomainUsername; + QStringList verifiedDomainUserGroups; + if (domainHasLogin() && !domainUsername.isEmpty()) { + + if (domainAccessToken.isEmpty()) { + // User is attempting to prove their domain identity. +#ifdef WANT_DEBUG + qDebug() << "Stalling login because we have no domain OAuth2 tokens:" << domainUsername; +#endif + return SharedNodePointer(); + + } else if (needToVerifyDomainUserIdentity(domainUsername, domainAccessToken, domainRefreshToken)) { + // User's domain identity needs to be confirmed. + requestDomainUser(domainUsername, domainAccessToken, domainRefreshToken); +#ifdef WANT_DEBUG + qDebug() << "Stalling login because we haven't authenticated user yet:" << domainUsername; +#endif + + } else if (verifyDomainUserIdentity(domainUsername, domainAccessToken, domainRefreshToken, + nodeConnection.senderSockAddr)) { + // User's domain identity is confirmed. + verifiedDomainUsername = domainUsername; + + } else { + // User's domain identity didn't check out. +#ifdef WANT_DEBUG + qDebug() << "Stalling login because domain user verification failed:" << domainUsername; +#endif + return SharedNodePointer(); + + } + } + + userPerms = setPermissionsForUser(isLocalUser, verifiedUsername, verifiedDomainUsername, + nodeConnection.senderSockAddr.getAddress(), nodeConnection.hardwareAddress, + nodeConnection.machineFingerprint); if (!userPerms.can(NodePermissions::Permission::canConnectToDomain)) { - sendConnectionDeniedPacket("You lack the required permissions to connect to this domain.", - nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorized); + if (domainHasLogin()) { + QString domainAuthURL; + auto domainAuthURLVariant = _server->_settingsManager.valueForKeyPath(AUTHENTICATION_OAUTH2_URL_PATH); + if (domainAuthURLVariant.canConvert()) { + domainAuthURL = domainAuthURLVariant.toString(); + } + QString domainAuthClientID; + auto domainAuthClientIDVariant = _server->_settingsManager.valueForKeyPath(AUTHENTICATION_PLUGIN_CLIENT_ID); + if (domainAuthClientIDVariant.canConvert()) { + domainAuthClientID = domainAuthClientIDVariant.toString(); + } + + sendConnectionDeniedPacket("You lack the required domain permissions to connect to this domain.", + nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedDomain, + domainAuthURL + "|" + domainAuthClientID); + } else { + sendConnectionDeniedPacket("You lack the required metaverse permissions to connect to this domain.", + nodeConnection.senderSockAddr, DomainHandler::ConnectionRefusedReason::NotAuthorizedMetaverse); + } #ifdef WANT_DEBUG qDebug() << "stalling login due to permissions:" << username; #endif @@ -600,15 +727,15 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, return true; } else { - // we only send back a LoginError if this wasn't an "optimistic" key + // we only send back a LoginErrorMetaverse if this wasn't an "optimistic" key // (a key that we hoped would work but is probably stale) if (!senderSockAddr.isNull() && !isOptimisticKey) { - qDebug() << "Error decrypting username signature for" << username << "- denying connection."; + qDebug() << "Error decrypting metaverse username signature for" << username << "- denying connection."; sendConnectionDeniedPacket("Error decrypting username signature.", senderSockAddr, - DomainHandler::ConnectionRefusedReason::LoginError); + DomainHandler::ConnectionRefusedReason::LoginErrorMetaverse); } else if (!senderSockAddr.isNull()) { - qDebug() << "Error decrypting username signature for" << username << "with optimisitic key -" + qDebug() << "Error decrypting metaverse username signature for" << username << "with optimistic key -" << "re-requesting public key and delaying connection"; } @@ -622,7 +749,7 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, if (!senderSockAddr.isNull()) { qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection."; sendConnectionDeniedPacket("Couldn't convert data to RSA key.", senderSockAddr, - DomainHandler::ConnectionRefusedReason::LoginError); + DomainHandler::ConnectionRefusedReason::LoginErrorMetaverse); } } } else { @@ -635,6 +762,25 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username, return false; } + +bool DomainGatekeeper::needToVerifyDomainUserIdentity(const QString& username, const QString& accessToken, + const QString& refreshToken) { + return !_verifiedDomainUserIdentities.contains(username) + || _verifiedDomainUserIdentities.value(username) != QPair(accessToken, refreshToken); +} + +bool DomainGatekeeper::verifyDomainUserIdentity(const QString& username, const QString& accessToken, + const QString& refreshToken, const HifiSockAddr& senderSockAddr) { + if (_verifiedDomainUserIdentities.contains(username) + && _verifiedDomainUserIdentities.value(username) == QPair(accessToken, refreshToken)) { + return true; + } + + sendConnectionDeniedPacket("Error verifying domain user.", senderSockAddr, + DomainHandler::ConnectionRefusedReason::LoginErrorDomain); + return false; +} + bool DomainGatekeeper::isWithinMaxCapacity() { // find out what our maximum capacity is QVariant maximumUserCapacityVariant = @@ -907,7 +1053,6 @@ void DomainGatekeeper::getGroupMemberships(const QString& username) { AccountManagerAuth::Required, QNetworkAccessManager::PostOperation, callbackParams, QJsonDocument(json).toJson()); - } QString extractUsernameFromGroupMembershipsReply(QNetworkReply* requestReply) { @@ -962,6 +1107,7 @@ void DomainGatekeeper::getIsGroupMemberErrorCallback(QNetworkReply* requestReply _inFlightGroupMembershipsRequests.remove(extractUsernameFromGroupMembershipsReply(requestReply)); } + void DomainGatekeeper::getDomainOwnerFriendsList() { JSONCallbackParameters callbackParams; callbackParams.callbackReceiver = this; @@ -1010,6 +1156,7 @@ void DomainGatekeeper::getDomainOwnerFriendsListErrorCallback(QNetworkReply* req qDebug() << "getDomainOwnerFriendsList api call failed:" << requestReply->error(); } +// ####### TODO: Domain equivalent or addition void DomainGatekeeper::refreshGroupsCache() { // if agents are connected to this domain, refresh our cached information about groups and memberships in such. getDomainOwnerFriendsList(); @@ -1029,7 +1176,7 @@ void DomainGatekeeper::refreshGroupsCache() { updateNodePermissions(); -#if WANT_DEBUG +#ifdef WANT_DEBUG _server->_settingsManager.debugDumpGroupsState(); #endif } @@ -1061,3 +1208,91 @@ Node::LocalID DomainGatekeeper::findOrCreateLocalID(const QUuid& uuid) { _localIDs.insert(newLocalID); return newLocalID; } + + +bool DomainGatekeeper::domainHasLogin() { + // The domain may have its own users and groups in a WordPress site. + return _server->_settingsManager.valueForKeyPath(AUTHENTICATION_ENABLE_OAUTH2).toBool() + && !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_OAUTH2_URL_PATH).toString().isEmpty() + && !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_WORDPRESS_URL_BASE).toString().isEmpty() + && !_server->_settingsManager.valueForKeyPath(AUTHENTICATION_PLUGIN_CLIENT_ID).toString().isEmpty(); +} + +void DomainGatekeeper::requestDomainUser(const QString& username, const QString& accessToken, const QString& refreshToken) { + + if (_inFlightDomainUserIdentityRequests.contains(username)) { + // Domain identify request for this username is already in progress. + return; + } + _inFlightDomainUserIdentityRequests.insert(username, QPair(accessToken, refreshToken)); + + if (_verifiedDomainUserIdentities.contains(username)) { + _verifiedDomainUserIdentities.remove(username); + } + + QString apiBase = _server->_settingsManager.valueForKeyPath(AUTHENTICATION_WORDPRESS_URL_BASE).toString(); + if (!apiBase.endsWith("/")) { + apiBase += "/"; + } + + // Get data pertaining to "me", the user who generated the access token. + const QString WORDPRESS_USER_ROUTE = "wp/v2/users/me"; + const QString WORDPRESS_USER_QUERY = "_fields=username,roles"; + QUrl domainUserURL = apiBase + WORDPRESS_USER_ROUTE + (apiBase.contains("?") ? "&" : "?") + WORDPRESS_USER_QUERY; + + QNetworkRequest request; + + request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + request.setRawHeader(QByteArray("Authorization"), QString("Bearer " + accessToken).toUtf8()); + + QByteArray formData; // No data to send. + + request.setUrl(domainUserURL); + + request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* requestReply = networkAccessManager.post(request, formData); + connect(requestReply, &QNetworkReply::finished, this, &DomainGatekeeper::requestDomainUserFinished); +} + +void DomainGatekeeper::requestDomainUserFinished() { + + QNetworkReply* requestReply = reinterpret_cast(sender()); + + QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll()); + const QJsonObject& rootObject = jsonResponse.object(); + + auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + if (200 <= httpStatus && httpStatus < 300) { + + QString username = rootObject.value("username").toString().toLower(); + if (_inFlightDomainUserIdentityRequests.contains(username)) { + // Success! Verified user. + _verifiedDomainUserIdentities.insert(username, _inFlightDomainUserIdentityRequests.value(username)); + _inFlightDomainUserIdentityRequests.remove(username); + + // User user's WordPress roles as domain groups. + QStringList domainUserGroups; + auto userRoles = rootObject.value("roles").toArray(); + foreach (auto role, userRoles) { + // Distinguish domain groups from metaverse groups by adding a leading special character. + domainUserGroups.append(DOMAIN_GROUP_CHAR + role.toString().toLower()); + } + _domainGroupMemberships[username] = domainUserGroups; + + } else { + // Failure. + qDebug() << "Unexpected username in response for user details -" << username; + } + + } else { + // Failure. + qDebug() << "Error in response for user details -" << httpStatus << requestReply->error() + << "-" << rootObject["error"].toString() << rootObject["error_description"].toString(); + + _inFlightDomainUserIdentityRequests.clear(); + } +} diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index 92b400882e..cb42baa7e3 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -4,6 +4,7 @@ // // Created by Stephen Birarda on 2015-08-24. // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -29,6 +30,8 @@ #include "NodeConnectionData.h" #include "PendingAssignedNodeData.h" +const QString DOMAIN_GROUP_CHAR = "@"; + class DomainServer; class DomainGatekeeper : public QObject { @@ -71,16 +74,28 @@ public slots: private slots: void handlePeerPingTimeout(); + + // Login and groups for domain, separate from metaverse. + void requestDomainUserFinished(); + private: SharedNodePointer processAssignmentConnectRequest(const NodeConnectionData& nodeConnection, const PendingAssignedNodeData& pendingAssignment); SharedNodePointer processAgentConnectRequest(const NodeConnectionData& nodeConnection, const QString& username, - const QByteArray& usernameSignature); + const QByteArray& usernameSignature, + const QString& domainUsername, + const QString& domainAccessToken, + const QString& domainRefreshToken); SharedNodePointer addVerifiedNodeFromConnectRequest(const NodeConnectionData& nodeConnection); bool verifyUserSignature(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr); + + bool needToVerifyDomainUserIdentity(const QString& username, const QString& accessToken, const QString& refreshToken); + bool verifyDomainUserIdentity(const QString& username, const QString& accessToken, const QString& refreshToken, + const HifiSockAddr& senderSockAddr); + bool isWithinMaxCapacity(); bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, @@ -120,8 +135,9 @@ private: QSet _domainOwnerFriends; // keep track of friends of the domain owner QSet _inFlightGroupMembershipsRequests; // keep track of which we've already asked for - NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, const QHostAddress& senderAddress, - const QString& hardwareAddress, const QUuid& machineFingerprint); + NodePermissions setPermissionsForUser(bool isLocalUser, QString verifiedUsername, QString verifiedDomainUsername, + const QHostAddress& senderAddress, const QString& hardwareAddress, + const QUuid& machineFingerprint); void getGroupMemberships(const QString& username); // void getIsGroupMember(const QString& username, const QUuid groupID); @@ -133,9 +149,18 @@ private: using LocalIDs = std::unordered_set; LocalIDs _localIDs; UUIDToLocalID _uuidToLocalID; - Node::LocalID _currentLocalID; Node::LocalID _idIncrement; + + // Login and groups for domain, separate from metaverse. + bool domainHasLogin(); + void requestDomainUser(const QString& username, const QString& accessToken, const QString& refreshToken); + + typedef QHash> DomainUserIdentities; // > + DomainUserIdentities _inFlightDomainUserIdentityRequests; // Domain user identity requests currently in progress. + DomainUserIdentities _verifiedDomainUserIdentities; // Verified domain users. + + QHash _domainGroupMemberships; // }; diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d7b813dd7d..ec0a8ff45d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -121,7 +121,7 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection, QUrl url{ MetaverseAPI::getCurrentMetaverseServerURL().toString() + metaversePath }; QNetworkRequest req(url); - req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + req.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); if (accessTokenVariant.isValid()) { @@ -2470,7 +2470,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url url.setQuery("access_token=" + accessTokenVariant.toString()); QNetworkRequest req(url); - req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + req.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QNetworkReply* reply = NetworkAccessManager::getInstance().put(req, doc.toJson()); @@ -2571,7 +2571,7 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u QNetworkRequest tokenRequest(tokenRequestUrl); tokenRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - tokenRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + tokenRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit()); @@ -2883,7 +2883,7 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR QNetworkRequest profileRequest(profileURL); profileRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - profileRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + profileRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); return NetworkAccessManager::getInstance().get(profileRequest); } diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 73d78a5c70..95bf4adc65 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -1966,6 +1966,10 @@ void DomainServerSettingsManager::apiRefreshGroupInformation() { QStringList groupNames = getAllKnownGroupNames(); foreach (QString groupName, groupNames) { QString lowerGroupName = groupName.toLower(); + if (lowerGroupName.startsWith(DOMAIN_GROUP_CHAR)) { + // Ignore domain groups. (Assumption: metaverse group names can't start with a "@".) + return; + } if (_groupIDs.contains(lowerGroupName)) { // we already know about this one. recall setGroupID in case the group has been // added to another section (the same group is found in both groups and blacklists). @@ -2185,6 +2189,24 @@ QList DomainServerSettingsManager::getBlacklistGroupIDs() { return result.toList(); } +QStringList DomainServerSettingsManager::getDomainServerGroupNames() { + // All names as listed in the domain server settings; both metaverse groups and domain groups + QSet result; + foreach(NodePermissionsKey groupKey, _groupPermissions.keys()) { + result += _groupPermissions[groupKey]->getID(); + } + return result.toList(); +} + +QStringList DomainServerSettingsManager::getDomainServerBlacklistGroupNames() { + // All names as listed in the domain server settings; not necessarily mnetaverse groups. + QSet result; + foreach (NodePermissionsKey groupKey, _groupForbiddens.keys()) { + result += _groupForbiddens[groupKey]->getID(); + } + return result.toList(); +} + void DomainServerSettingsManager::debugDumpGroupsState() { qDebug() << "--------- GROUPS ---------"; diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index e28b9f6cd1..294e441ba4 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -19,11 +19,11 @@ #include #include - -#include -#include "NodePermissions.h" - #include +#include + +#include "DomainGatekeeper.h" +#include "NodePermissions.h" const QString SETTINGS_PATHS_KEY = "paths"; @@ -105,6 +105,9 @@ public: QList getGroupIDs(); QList getBlacklistGroupIDs(); + QStringList getDomainServerGroupNames(); + QStringList getDomainServerBlacklistGroupNames(); + // these are used to locally cache the result of calling "api/v1/groups/.../is_member/..." on metaverse's api void clearGroupMemberships(const QString& name) { _groupMembership[name.toLower()].clear(); } void recordGroupMembership(const QString& name, const QUuid groupID, QUuid rankID); diff --git a/hifi_android.py b/hifi_android.py index 0c2ea07cc7..a8fec01035 100644 --- a/hifi_android.py +++ b/hifi_android.py @@ -10,87 +10,74 @@ import zipfile print = functools.partial(print, flush=True) -ANDROID_PACKAGE_URL = 'https://hifi-public.s3.amazonaws.com/dependencies/android/' +ANDROID_PACKAGE_URL = 'https://content.vircadia.com/eu-c-1/vircadia-public/dependencies/android/' ANDROID_PACKAGES = { 'qt' : { 'file': 'qt-5.11.1_linux_armv8-libcpp_openssl_patched.tgz', - 'versionId': '3S97HBM5G5Xw9EfE52sikmgdN3t6C2MN', 'checksum': 'aa449d4bfa963f3bc9a9dfe558ba29df', }, 'bullet': { 'file': 'bullet-2.88_armv8-libcpp.tgz', - 'versionId': 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg', 'checksum': '81642779ccb110f8c7338e8739ac38a0', }, 'draco': { 'file': 'draco_armv8-libcpp.tgz', - 'versionId': '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8', 'checksum': '617a80d213a5ec69fbfa21a1f2f738cd', }, 'glad': { 'file': 'glad_armv8-libcpp.zip', - 'versionId': 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY', 'checksum': 'a8ee8584cf1ccd34766c7ddd9d5e5449', }, 'gvr': { 'file': 'gvrsdk_v1.101.0.tgz', - 'versionId': 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r', 'checksum': '57fd02baa069176ba18597a29b6b4fc7', }, 'nvtt': { 'file': 'nvtt_armv8-libcpp.zip', - 'versionId': 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO', 'checksum': 'eb46d0b683e66987190ed124aabf8910', 'sharedLibFolder': 'lib', 'includeLibs': ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so'] }, 'oculus_1.22': { 'file': 'ovr_sdk_mobile_1.22.zip', - 'versionId': 'InhomR5gwkzyiLAelH3X9k4nvV3iIpA_', 'checksum': '1ac3c5b0521e5406f287f351015daff8', 'sharedLibFolder': 'VrApi/Libs/Android/arm64-v8a/Release', 'includeLibs': ['libvrapi.so'] }, 'oculusPlatform': { 'file': 'OVRPlatformSDK_v1.34.0.zip', - 'versionId': 'vbRUkkyzUAXfTGSEtuiUr_7.Fm5h5BZk', 'checksum': '16e4c5f39520f122bc49cb6d5bb88289', 'sharedLibFolder': 'Android/libs/arm64-v8a', 'includeLibs': ['libovrplatformloader.so'] }, 'openssl': { 'file': 'openssl-1.1.0g_armv8.tgz', - 'versionId': 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW', 'checksum': 'cabb681fbccd79594f65fcc266e02f32' }, 'polyvox': { 'file': 'polyvox_armv8-libcpp.tgz', - 'versionId': 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92', 'checksum': 'dba88b3a098747af4bb169e9eb9af57e', 'sharedLibFolder': 'lib', 'includeLibs': ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'], }, 'tbb': { 'file': 'tbb-2018_U1_armv8_libcpp.tgz', - 'versionId': 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB', 'checksum': '20768f298f53b195e71b414b0ae240c4', 'sharedLibFolder': 'lib/release', 'includeLibs': ['libtbb.so', 'libtbbmalloc.so'], }, 'hifiAC': { - 'baseUrl': 'http://s3.amazonaws.com/hifi-public/dependencies/', + 'baseUrl': 'https://content.vircadia.com/eu-c-1/vircadia-public/dependencies/', 'file': 'codecSDK-android_armv8-2.0.zip', 'checksum': '1cbef929675818fc64c4101b72f84a6a' }, 'etc2comp': { 'file': 'etc2comp-patched-armv8-libcpp.tgz', - 'versionId': 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU', 'checksum': '14b02795d774457a33bbc60e00a786bc' }, 'breakpad': { 'file': 'breakpad.tgz', - 'versionId': '8VrYXz7oyc.QBxNia0BVJOUBvrFO61jI', 'checksum': 'ddcb23df336b08017042ba4786db1d9e', 'sharedLibFolder': 'lib', 'includeLibs': {'libbreakpad_client.a'} @@ -105,14 +92,12 @@ ANDROID_PLATFORM_PACKAGES = { 'Darwin' : { 'qt': { 'file': 'qt-5.11.1_osx_armv8-libcpp_openssl_patched.tgz', - 'versionId': 'OxBD7iKINv1HbyOXmAmDrBb8AF3N.Kup', 'checksum': 'c83cc477c08a892e00c71764dca051a0' }, }, 'Windows' : { 'qt': { 'file': 'qt-5.11.1_win_armv8-libcpp_openssl_patched.tgz', - 'versionId': 'JfWM0P_Mz5Qp0LwpzhrsRwN3fqlLSFeT', 'checksum': '0582191cc55431aa4f660848a542883e' }, } diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 1a0e279674..608bbb19cc 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -121,14 +121,14 @@ if (APPLE) # configure CMake to use a custom Info.plist set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in) - set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity") + set(MACOSX_BUNDLE_BUNDLE_NAME "Vircadia") if (PRODUCTION_BUILD) - set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface) + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.vircadia.interface) else () if (DEV_BUILD) - set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-dev) + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.vircadia.interface-dev) elseif (PR_BUILD) - set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface-pr) + set(MACOSX_BUNDLE_GUI_IDENTIFIER com.vircadia.interface-pr) endif () endif () diff --git a/interface/resources/qml/ConnectionFailureDialog.qml b/interface/resources/qml/ConnectionFailureDialog.qml index 0d5bdfd38d..ab1e7a096c 100644 --- a/interface/resources/qml/ConnectionFailureDialog.qml +++ b/interface/resources/qml/ConnectionFailureDialog.qml @@ -7,7 +7,7 @@ MessageDialog { objectName: "ConnectionFailureDialog" title: "No Connection" - text: "Unable to connect to this domain. Click the 'GO TO' button on the toolbar to visit another domain." + text: "Unable to connect to this domain. Click the 'EXPLORE' button on the toolbar to visit another domain." buttons: OriginalDialogs.StandardButton.Ok icon: OriginalDialogs.StandardIcon.Warning defaultButton: OriginalDialogs.StandardButton.NoButton; diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 571b7e074c..694fd6158f 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -45,6 +45,9 @@ Item { property bool lostFocus: false readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() + // If not logging into domain, then we must be logging into the metaverse... + readonly property bool isLoggingInToDomain: loginDialog.getDomainLoginRequested() + readonly property string domainLoginDomain: loginDialog.getDomainLoginDomain() QtObject { id: d @@ -71,7 +74,12 @@ Item { } function login() { - loginDialog.login(emailField.text, passwordField.text); + if (!isLoggingInToDomain) { + loginDialog.login(emailField.text, passwordField.text); + } else { + loginDialog.loginDomain(emailField.text, passwordField.text); + } + if (linkAccountBody.loginDialogPoppedUp) { var data; if (linkAccountBody.linkSteam) { @@ -87,7 +95,7 @@ Item { } bodyLoader.setSource("LoggingInBody.qml", { "loginDialog": loginDialog, "root": root, "bodyLoader": bodyLoader, "withSteam": linkAccountBody.withSteam, "withOculus": linkAccountBody.withOculus, "linkSteam": linkAccountBody.linkSteam, "linkOculus": linkAccountBody.linkOculus, - "displayName":displayNameField.text }); + "displayName":displayNameField.text, "isLoggingInToDomain": linkAccountBody.isLoggingInToDomain, "domainLoginDomain": linkAccountBody.domainLoginDomain }); } function init() { @@ -98,14 +106,22 @@ Item { loginErrorMessage.wrapMode = Text.WordWrap; errorContainer.height = (loginErrorMessageTextMetrics.width / displayNameField.width) * loginErrorMessageTextMetrics.height; } + var domainLoginText = "Log In to Domain\n" + domainLoginDomain; + loginDialogText.text = (!isLoggingInToDomain) ? "Log In to Metaverse" : domainLoginText; loginButton.text = (!linkAccountBody.linkSteam && !linkAccountBody.linkOculus) ? "Log In" : "Link Account"; + loginButton.text = (!isLoggingInToDomain) ? "Log In to Metaverse" : "Log In to Domain"; loginButton.color = hifi.buttons.blue; displayNameField.placeholderText = "Display Name (optional)"; var savedDisplayName = Settings.getValue("Avatar/displayName", ""); displayNameField.text = savedDisplayName; - emailField.placeholderText = "Username or Email"; - var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", ""); - emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : ""; + emailField.placeholderText = (!isLoggingInToDomain) ? "Username or Email" : "Username"; + if (!isLoggingInToDomain) { + var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", ""); + emailField.text = keepMeLoggedInCheckbox.checked ? savedUsername === "Unknown user" ? "" : savedUsername : ""; + } else { + // ####### TODO + } + if (linkAccountBody.linkSteam || linkAccountBody.linkOculus) { loginButton.width = (passwordField.width - hifi.dimensions.contentSpacing.x) / 2; loginButton.anchors.right = displayNameField.right; @@ -131,7 +147,7 @@ Item { Item { id: loginContainer width: displayNameField.width - height: errorContainer.height + displayNameField.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y + + height: errorContainer.height + loginDialogTextContainer.height + displayNameField.height + emailField.height + passwordField.height + 5.5 * hifi.dimensions.contentSpacing.y + keepMeLoggedInCheckbox.height + loginButton.height + cantAccessTextMetrics.height + continueButton.height anchors { top: parent.top @@ -145,9 +161,10 @@ Item { width: parent.width height: loginErrorMessageTextMetrics.height anchors { - bottom: displayNameField.top; - bottomMargin: hifi.dimensions.contentSpacing.y; - left: displayNameField.left; + bottom: loginDialogTextContainer.top + bottomMargin: hifi.dimensions.contentSpacing.y + left: loginDialogTextContainer.left + right: loginDialogTextContainer.right } TextMetrics { id: loginErrorMessageTextMetrics @@ -160,12 +177,45 @@ Item { font.family: linkAccountBody.fontFamily font.pixelSize: linkAccountBody.textFieldFontSize font.bold: linkAccountBody.fontBold + anchors { + top: parent.top + left: parent.left + right: parent.right + } verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter text: "" visible: false } } + + Item { + id: loginDialogTextContainer + height: 56 + anchors { + top: parent.top + left: parent.left + right: parent.right + topMargin: 1.5 * hifi.dimensions.contentSpacing.y + } + + Text { + id: loginDialogText + text: qsTr("Log In") + lineHeight: 1 + color: "white" + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.family: linkAccountBody.fontFamily + font.pixelSize: 24 + font.bold: linkAccountBody.fontBold + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + } + } HifiControlsUit.TextField { id: displayNameField @@ -174,8 +224,8 @@ Item { font.pixelSize: linkAccountBody.textFieldFontSize styleRenderType: Text.QtRendering anchors { - top: parent.top - topMargin: errorContainer.height + top: loginDialogTextContainer.bottom + topMargin: 1.5 * hifi.dimensions.contentSpacing.y } placeholderText: "Display Name (optional)" activeFocusOnPress: true @@ -193,7 +243,11 @@ Item { case Qt.Key_Return: event.accepted = true; if (keepMeLoggedInCheckbox.checked) { - Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + if (!isLoggingInToDomain) { + Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + } else { + // ####### TODO + } } linkAccountBody.login(); break; @@ -232,7 +286,11 @@ Item { case Qt.Key_Return: event.accepted = true; if (keepMeLoggedInCheckbox.checked) { - Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + if (!isLoggingInToDomain) { + Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + } else { + // ####### TODO + } } linkAccountBody.login(); break; @@ -312,7 +370,11 @@ Item { case Qt.Key_Return: event.accepted = true; if (keepMeLoggedInCheckbox.checked) { - Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + if (!isLoggingInToDomain) { + Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + } else { + // ####### TODO + } } linkAccountBody.login(); break; @@ -321,12 +383,13 @@ Item { } HifiControlsUit.CheckBox { id: keepMeLoggedInCheckbox - checked: Settings.getValue("keepMeLoggedIn", false); + checked: !isLoggingInToDomain ? Settings.getValue("keepMeLoggedIn", false) : false; // ####### TODO text: qsTr("Keep Me Logged In"); boxSize: 18; labelFontFamily: linkAccountBody.fontFamily labelFontSize: 18; color: hifi.colors.white; + visible: !isLoggingInToDomain anchors { top: passwordField.bottom; topMargin: hifi.dimensions.contentSpacing.y; @@ -334,14 +397,22 @@ Item { } onCheckedChanged: { Settings.setValue("keepMeLoggedIn", checked); - if (keepMeLoggedInCheckbox.checked) { - Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + if (!isLoggingInToDomain) { + if (keepMeLoggedInCheckbox.checked) { + Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text); + } else { + Settings.setValue("keepMeLoggedIn/savedUsername", ""); + } } else { - Settings.setValue("keepMeLoggedIn/savedUsername", ""); + // ####### TODO } } Component.onCompleted: { - keepMeLoggedInCheckbox.checked = !Account.loggedIn; + if (!isLoggingInToDomain) { + keepMeLoggedInCheckbox.checked = !Account.loggedIn; + } else { + // ####### TODO + } } } HifiControlsUit.Button { @@ -393,7 +464,7 @@ Item { HifiStylesUit.ShortcutText { id: cantAccessText z: 10 - visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus + visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus && !linkAccountBody.isLoggingInToDomain anchors { top: loginButton.bottom topMargin: hifi.dimensions.contentSpacing.y @@ -403,7 +474,7 @@ Item { font.pixelSize: linkAccountBody.textFieldFontSize font.bold: linkAccountBody.fontBold - text: " Can't access your account?" + text: " Can't access your account?" verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter @@ -492,7 +563,7 @@ Item { id: signUpContainer width: loginContainer.width height: signUpTextMetrics.height - visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus + visible: !linkAccountBody.linkSteam && !linkAccountBody.linkOculus && !linkAccountBody.isLoggingInToDomain anchors { left: loginContainer.left top: loginContainer.bottom @@ -529,7 +600,7 @@ Item { leftMargin: hifi.dimensions.contentSpacing.x } - text: "Sign Up" + text: "Sign Up" linkColor: hifi.colors.blueAccent onLinkActivated: { diff --git a/interface/resources/qml/LoginDialog/LoggingInBody.qml b/interface/resources/qml/LoginDialog/LoggingInBody.qml index a0029dc40b..757c8b7449 100644 --- a/interface/resources/qml/LoginDialog/LoggingInBody.qml +++ b/interface/resources/qml/LoginDialog/LoggingInBody.qml @@ -3,6 +3,7 @@ // // Created by Wayne Chen on 10/18/18 // Copyright 2018 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -31,6 +32,8 @@ Item { property bool linkSteam: linkSteam property bool linkOculus: linkOculus property bool createOculus: createOculus + property bool isLoggingInToDomain: isLoggingInToDomain + property string domainLoginDomain: domainLoginDomain property string displayName: "" readonly property bool loginDialogPoppedUp: loginDialog.getLoginDialogPoppedUp() @@ -106,6 +109,9 @@ Item { loggingInGlyph.visible = true; loggingInText.text = "Logging in to Oculus"; loggingInText.x = loggingInHeader.width/2 - loggingInTextMetrics.width/2 + loggingInGlyphTextMetrics.width/2; + } else if (loggingInBody.isLoggingInToDomain) { + loggingInText.text = "Logging in to " + domainLoginDomain; + loggingInText.anchors.centerIn = loggingInHeader; } else { loggingInText.text = "Logging in"; loggingInText.anchors.centerIn = loggingInHeader; diff --git a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml index a36b6791a4..e9546748c0 100644 --- a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml @@ -137,7 +137,7 @@ Item { if (webViewCoreUserAgent !== undefined) { webViewCore.profile.httpUserAgent = webViewCoreUserAgent } else { - webViewCore.profile.httpUserAgent += " (HighFidelityInterface)"; + webViewCore.profile.httpUserAgent += " (VircadiaInterface)"; } // Ensure the JS from the web-engine makes it to our logging webViewCore.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { diff --git a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml index 544824135e..17292d2923 100644 --- a/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml +++ b/interface/resources/qml/dialogs/TabletConnectionFailureDialog.qml @@ -19,7 +19,7 @@ Item { buttons: OriginalDialogs.StandardButton.Ok, defaultButton: OriginalDialogs.StandardButton.NoButton, title: "No Connection", - text: "Unable to connect to this domain. Click the 'GO TO' button on the toolbar to visit another domain." + text: "Unable to connect to this domain. Click the 'EXPLORE' button on the toolbar to visit another domain." }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Ok) { diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index 963a3246fc..31f3ee44df 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -6,6 +6,7 @@ // // Created by Vlad Stelmahovsky on 03/22/2017 // Copyright 2017 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -325,178 +326,14 @@ Rectangle { size: 16; text: (bar.currentIndex === 0) ? qsTr("Press and hold the button \"T\" to talk.") : - qsTr("Press and hold grip triggers on both of your controllers to talk."); - } - } - - Separator { - id: secondSeparator; - anchors.top: pttTextContainer.visible ? pttTextContainer.bottom : switchesContainer.bottom; - anchors.topMargin: 10; - } - - Item { - id: inputDeviceHeader - x: margins.paddings; - width: parent.width - margins.paddings*2; - height: 36; - anchors.top: secondSeparator.bottom; - anchors.topMargin: 10; - - HiFiGlyphs { - width: margins.sizeCheckBox; - text: hifi.glyphs.mic; - color: hifi.colors.white; - anchors.left: parent.left; - anchors.leftMargin: -size/4; //the glyph has empty space at left about 25% - anchors.verticalCenter: parent.verticalCenter; - size: 30; - } - RalewayRegular { - anchors.verticalCenter: parent.verticalCenter; - width: margins.sizeText + margins.sizeLevel; - anchors.left: parent.left; - anchors.leftMargin: margins.sizeCheckBox; - size: 22; - color: hifi.colors.white; - text: qsTr("Choose input device"); - } - } - - ListView { - id: inputView; - width: rightMostInputLevelPos; - anchors.top: inputDeviceHeader.bottom; - anchors.topMargin: 10; - x: margins.paddings - interactive: false; - height: contentHeight; - - clip: true; - model: AudioScriptingInterface.devices.input; - delegate: Item { - width: rightMostInputLevelPos - margins.paddings*2 - height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? - (margins.sizeCheckBox > checkBoxInput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxInput.implicitHeight + 4) : 0 - visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) - AudioControls.CheckBox { - id: checkBoxInput - anchors.left: parent.left - spacing: margins.sizeCheckBox - boxSize - anchors.verticalCenter: parent.verticalCenter - width: parent.width - inputLevel.width - clip: true - checkable: !checked - checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; - boxSize: margins.sizeCheckBox / 2 - isRound: true - text: devicename - fontSize: 16; - onPressed: { - if (!checked) { - stereoInput.checked = false; - AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo - AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); - } - } - } - AudioControls.InputPeak { - id: inputLevel - anchors.right: parent.right - peak: model.peak; - anchors.verticalCenter: parent.verticalCenter - visible: ((bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR)) && - AudioScriptingInterface.devices.input.peakValuesAvailable; - } - } - } - - AudioControls.LoopbackAudio { - id: loopbackAudio - x: margins.paddings - anchors.top: inputView.bottom; - anchors.topMargin: 10; - - visible: (bar.currentIndex === 1 && isVR) || - (bar.currentIndex === 0 && !isVR); - anchors { left: parent.left; leftMargin: margins.paddings } - } - - Separator { - id: thirdSeparator; - anchors.top: loopbackAudio.visible ? loopbackAudio.bottom : inputView.bottom; - anchors.topMargin: 10; - } - - Item { - id: outputDeviceHeader; - anchors.topMargin: 10; - anchors.top: thirdSeparator.bottom; - x: margins.paddings; - width: parent.width - margins.paddings*2 - height: 36 - - HiFiGlyphs { - anchors.left: parent.left - anchors.leftMargin: -size/4 //the glyph has empty space at left about 25% - anchors.verticalCenter: parent.verticalCenter; - width: margins.sizeCheckBox - text: hifi.glyphs.unmuted; - color: hifi.colors.white; - size: 36; - } - - RalewayRegular { - width: margins.sizeText + margins.sizeLevel - anchors.left: parent.left - anchors.leftMargin: margins.sizeCheckBox - anchors.verticalCenter: parent.verticalCenter; - size: 22; - color: hifi.colors.white; - text: qsTr("Choose output device"); - } - } - - ListView { - id: outputView - width: parent.width - margins.paddings*2 - x: margins.paddings; - interactive: false; - height: contentHeight; - anchors.top: outputDeviceHeader.bottom; - anchors.topMargin: 10; - clip: true; - model: AudioScriptingInterface.devices.output; - delegate: Item { - width: rightMostInputLevelPos - height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? - (margins.sizeCheckBox > checkBoxOutput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxOutput.implicitHeight + 4) : 0 - visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) - - AudioControls.CheckBox { - id: checkBoxOutput - width: parent.width - spacing: margins.sizeCheckBox - boxSize - boxSize: margins.sizeCheckBox / 2 - isRound: true - checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; - checkable: !checked - text: devicename - fontSize: 16 - onPressed: { - if (!checked) { - AudioScriptingInterface.setOutputDevice(info, bar.currentIndex === 1); - } - } - } + qsTr("Press and hold grip triggers on both controllers to talk."); } } Item { id: avatarGainContainer x: margins.paddings; - anchors.top: outputView.bottom; + anchors.top: pttTextContainer.bottom; anchors.topMargin: 10; width: parent.width - margins.paddings*2 height: avatarGainSliderTextMetrics.height @@ -677,12 +514,174 @@ Rectangle { } } - AudioControls.PlaySampleSound { - id: playSampleSound - x: margins.paddings + Separator { + id: secondSeparator; anchors.top: systemInjectorGainContainer.bottom; anchors.topMargin: 10; } - } -} + Item { + id: inputDeviceHeader + x: margins.paddings; + width: parent.width - margins.paddings*2; + height: 36; + anchors.top: secondSeparator.bottom; + anchors.topMargin: 10; + + HiFiGlyphs { + width: margins.sizeCheckBox; + text: hifi.glyphs.mic; + color: hifi.colors.white; + anchors.left: parent.left; + anchors.leftMargin: -size/4; //the glyph has empty space at left about 25% + anchors.verticalCenter: parent.verticalCenter; + size: 30; + } + + RalewayRegular { + anchors.verticalCenter: parent.verticalCenter; + width: margins.sizeText + margins.sizeLevel; + anchors.left: parent.left; + anchors.leftMargin: margins.sizeCheckBox; + size: 22; + color: hifi.colors.white; + text: qsTr("Choose input device"); + } + } + + AudioControls.LoopbackAudio { + id: loopbackAudio + x: margins.paddings + anchors.top: inputDeviceHeader.bottom; + anchors.topMargin: 10; + visible: (bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR); + anchors { left: parent.left; leftMargin: margins.paddings } + } + + ListView { + id: inputView; + width: rightMostInputLevelPos; + anchors.top: loopbackAudio.visible ? loopbackAudio.bottom : inputDeviceHeader.bottom; + anchors.topMargin: 10; + x: margins.paddings + interactive: false; + height: contentHeight; + + clip: true; + model: AudioScriptingInterface.devices.input; + delegate: Item { + width: rightMostInputLevelPos - margins.paddings*2 + height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? + (margins.sizeCheckBox > checkBoxInput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxInput.implicitHeight + 4) : 0 + visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) + AudioControls.CheckBox { + id: checkBoxInput + anchors.left: parent.left + spacing: margins.sizeCheckBox - boxSize + anchors.verticalCenter: parent.verticalCenter + width: parent.width - inputLevel.width + clip: true + checkable: !checked + checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; + boxSize: margins.sizeCheckBox / 2 + isRound: true + text: devicename + fontSize: 16; + onPressed: { + if (!checked) { + stereoInput.checked = false; + AudioScriptingInterface.setStereoInput(false); // the next selected audio device might not support stereo + AudioScriptingInterface.setInputDevice(info, bar.currentIndex === 1); + } + } + } + AudioControls.InputPeak { + id: inputLevel + anchors.right: parent.right + peak: model.peak; + anchors.verticalCenter: parent.verticalCenter + visible: ((bar.currentIndex === 1 && isVR) || + (bar.currentIndex === 0 && !isVR)) && + AudioScriptingInterface.devices.input.peakValuesAvailable; + } + } + } + + Separator { + id: thirdSeparator; + anchors.top: inputView.bottom; + anchors.topMargin: 10; + } + + Item { + id: outputDeviceHeader; + anchors.topMargin: 10; + anchors.top: thirdSeparator.bottom; + x: margins.paddings; + width: parent.width - margins.paddings*2 + height: 36 + + HiFiGlyphs { + anchors.left: parent.left + anchors.leftMargin: -size/4 //the glyph has empty space at left about 25% + anchors.verticalCenter: parent.verticalCenter; + width: margins.sizeCheckBox + text: hifi.glyphs.unmuted; + color: hifi.colors.white; + size: 36; + } + + RalewayRegular { + width: margins.sizeText + margins.sizeLevel + anchors.left: parent.left + anchors.leftMargin: margins.sizeCheckBox + anchors.verticalCenter: parent.verticalCenter; + size: 22; + color: hifi.colors.white; + text: qsTr("Choose output device"); + } + } + + AudioControls.PlaySampleSound { + id: playSampleSound + x: margins.paddings + anchors.top: outputDeviceHeader.bottom; + anchors.topMargin: 10; + } + + ListView { + id: outputView + width: parent.width - margins.paddings*2 + x: margins.paddings; + interactive: false; + height: contentHeight + 10; + anchors.top: playSampleSound.bottom; + anchors.topMargin: 10; + clip: true; + model: AudioScriptingInterface.devices.output; + delegate: Item { + width: rightMostInputLevelPos + height: ((type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1)) ? + (margins.sizeCheckBox > checkBoxOutput.implicitHeight ? margins.sizeCheckBox + 4 : checkBoxOutput.implicitHeight + 4) : 0 + visible: (type != "hmd" && bar.currentIndex === 0) || (type != "desktop" && bar.currentIndex === 1) + AudioControls.CheckBox { + id: checkBoxOutput + width: parent.width + spacing: margins.sizeCheckBox - boxSize + boxSize: margins.sizeCheckBox / 2 + isRound: true + checked: bar.currentIndex === 0 ? selectedDesktop : selectedHMD; + checkable: !checked + text: devicename + fontSize: 16 + onPressed: { + if (!checked) { + AudioScriptingInterface.setOutputDevice(info, bar.currentIndex === 1); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml b/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml index 3b6502cc98..6e345caaf7 100644 --- a/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml +++ b/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml @@ -336,8 +336,8 @@ Item { height: parent.height colorScheme: hifi.colorSchemes.dark minimumValue: 0.25 - maximumValue: 1.0 - stepSize: 0.02 + maximumValue: 2.0 + stepSize: 0.05 value: Render.viewportResolutionScale live: true diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index 5db784789e..ea694ae2d7 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -1,6 +1,7 @@ // // Created by Dante Ruiz on 6/1/17. // Copyright 2017 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -96,7 +97,8 @@ Item { HifiControls.ImageMessageBox { id: imageMessageBox - anchors.fill: parent + anchors.top: parent.top + anchors.topMargin: 444 z: 2000 imageWidth: 442 imageHeight: 670 @@ -179,7 +181,7 @@ Item { HifiControls.CheckBox { id: checkBox colorScheme: hifi.colorSchemes.dark - text: "show all input devices" + text: "Show all input devices" onClicked: { box.model = inputPlugins(); diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index a9d67fec35..f1275a39fb 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -1,6 +1,7 @@ // // Created by Dante Ruiz on 6/5/17. // Copyright 2017 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -71,6 +72,7 @@ Flickable { property int state: buttonState.disabled property var lastConfiguration: null + property bool isConfiguring: false HifiConstants { id: hifi } @@ -360,9 +362,9 @@ Flickable { RalewayRegular { id: info - text: "See Recommended Tracker Placement" + text: "See Recommended Placement" color: hifi.colors.blueHighlight - size: 10 + size: 12 anchors { left: additional.right leftMargin: 10 @@ -415,7 +417,6 @@ Flickable { id: feetBox width: 15 height: 15 - boxRadius: 7 onClicked: { if (!checked) { @@ -446,7 +447,6 @@ Flickable { id: hipBox width: 15 height: 15 - boxRadius: 7 onClicked: { if (checked) { @@ -486,7 +486,6 @@ Flickable { id: chestBox width: 15 height: 15 - boxRadius: 7 onClicked: { if (checked) { @@ -524,7 +523,6 @@ Flickable { id: shoulderBox width: 15 height: 15 - boxRadius: 7 onClicked: { if (checked) { @@ -823,7 +821,6 @@ Flickable { id: viveInDesktop width: 15 height: 15 - boxRadius: 7 anchors.top: advanceSettings.bottom anchors.topMargin: 5 @@ -840,9 +837,71 @@ Flickable { } } + + HifiControls.CheckBox { + id: eyeTracking + width: 15 + height: 15 + + anchors.top: viveInDesktop.bottom + anchors.topMargin: 5 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 10 + + onClicked: { + sendConfigurationSettings(); + } + } + + RalewayBold { + id: eyeTrackingLabel + size: 12 + text: "Use eye tracking (if available)." + color: hifi.colors.lightGrayText + anchors { + left: eyeTracking.right + leftMargin: 5 + verticalCenter: eyeTracking.verticalCenter + } + } + + RalewayRegular { + id: privacyPolicy + text: "Privacy Policy" + color: hifi.colors.blueHighlight + size: 12 + anchors { + left: eyeTrackingLabel.right + leftMargin: 10 + verticalCenter: eyeTrackingLabel.verticalCenter + } + + Rectangle { + id: privacyPolicyUnderline + color: hifi.colors.blueHighlight + width: privacyPolicy.width + height: 1 + anchors { + top: privacyPolicy.bottom + topMargin: 1 + left: privacyPolicy.left + } + visible: false + } + + MouseArea { + anchors.fill: parent; + hoverEnabled: true + onEntered: privacyPolicyUnderline.visible = true; + onExited: privacyPolicyUnderline.visible = false; + onClicked: HiFiAbout.openUrl("https://vircadia.com/privacy-policy"); + } + } + + Row { id: outOfRangeDataStrategyRow - anchors.top: viveInDesktop.bottom + anchors.top: eyeTracking.bottom anchors.topMargin: 5 anchors.left: openVrConfiguration.left anchors.leftMargin: leftMargin + 10 @@ -966,6 +1025,8 @@ Flickable { } function displayConfiguration() { + isConfiguring = true; + var settings = InputConfiguration.configurationSettings(openVrConfiguration.pluginName); var configurationType = settings["trackerConfiguration"]; displayTrackerConfiguration(configurationType); @@ -982,6 +1043,7 @@ Flickable { var viveController = settings["handController"]; var desktopMode = settings["desktopMode"]; var hmdDesktopPosition = settings["hmdDesktopTracking"]; + var eyeTrackingEnabled = settings["eyeTrackingEnabled"]; armCircumference.realValue = settings.armCircumference; shoulderWidth.realValue = settings.shoulderWidth; @@ -1004,6 +1066,7 @@ Flickable { viveInDesktop.checked = desktopMode; hmdInDesktop.checked = hmdDesktopPosition; + eyeTracking.checked = eyeTrackingEnabled; outOfRangeDataStrategyComboBox.currentIndex = outOfRangeDataStrategyComboBox.model.indexOf(settings.outOfRangeDataStrategy); initializeButtonState(); @@ -1014,6 +1077,8 @@ Flickable { }; UserActivityLogger.logAction("mocap_ui_open_dialog", data); + + isConfiguring = false; } function displayTrackerConfiguration(type) { @@ -1170,6 +1235,7 @@ Flickable { "shoulderWidth": shoulderWidth.realValue, "desktopMode": viveInDesktop.checked, "hmdDesktopTracking": hmdInDesktop.checked, + "eyeTrackingEnabled": eyeTracking.checked, "outOfRangeDataStrategy": outOfRangeDataStrategyComboBox.model[outOfRangeDataStrategyComboBox.currentIndex] } @@ -1177,6 +1243,10 @@ Flickable { } function sendConfigurationSettings() { + if (isConfiguring) { + // Ignore control value changes during dialog initialization. + return; + } var settings = composeConfigurationSettings(); InputConfiguration.setConfigurationSettings(settings, openVrConfiguration.pluginName); updateCalibrationButton(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05ddcd5bd3..cc2aed7f53 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4,6 +4,7 @@ // // Created by Andrzej Kapolka on 5/10/13. // Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -65,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -852,6 +854,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { #else DependencyManager::set(true, std::bind(&Application::getUserAgent, qApp)); #endif + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT, defaultScriptsOverrideOption); DependencyManager::set(); @@ -1348,6 +1351,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo #endif connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); + auto domainAccountManager = DependencyManager::get(); + connect(domainAccountManager.data(), &DomainAccountManager::authRequired, dialogsManager.data(), + &DialogsManager::showDomainLoginDialog); + connect(domainAccountManager.data(), &DomainAccountManager::loginComplete, this, + &Application::updateWindowTitle); + // ####### TODO: Connect any other signals from domainAccountManager. + // use our MyAvatar position and quat for address manager path addressManager->setPositionGetter([] { auto avatarManager = DependencyManager::get(); @@ -1571,7 +1581,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Do not show login dialog if requested not to on the command line QString hifiNoLoginCommandLineKey = QString("--").append(HIFI_NO_LOGIN_COMMAND_LINE_KEY); int index = arguments().indexOf(hifiNoLoginCommandLineKey); - if (index != -1) { + if (index != -1 || _disableLoginScreen) { resumeAfterLoginDialogActionTaken(); return; } @@ -2614,7 +2624,7 @@ QString Application::getUserAgent() { return userAgent; } - QString userAgent = "Mozilla/5.0 (HighFidelityInterface/" + BuildInfo::VERSION + "; " + QString userAgent = NetworkingConstants::VIRCADIA_USER_AGENT + "/" + BuildInfo::VERSION + "; " + QSysInfo::productType() + " " + QSysInfo::productVersion() + ")"; auto formatPluginName = [](QString name) -> QString { return name.trimmed().replace(" ", "-"); }; @@ -2801,6 +2811,7 @@ void Application::cleanupBeforeQuit() { if (!keepMeLoggedIn) { DependencyManager::get()->removeAccountFromFile(); } + // ####### TODO _displayPlugin.reset(); PluginManager::getInstance()->shutdown(); @@ -3150,6 +3161,7 @@ extern void setupPreferences(); static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, int index, bool active = false); #endif +// ####### TODO void Application::showLoginScreen() { #if !defined(DISABLE_QML) auto accountManager = DependencyManager::get(); @@ -3857,6 +3869,11 @@ void Application::showHelp() { //InfoView::show(INFO_HELP_PATH, false, queryString.toString()); } +void Application::gotoTutorial() { + const QString TUTORIAL_ADDRESS = "file:///~/serverless/tutorial.json"; + DependencyManager::get()->handleLookupString(TUTORIAL_ADDRESS); +} + void Application::resizeEvent(QResizeEvent* event) { resizeGL(); } @@ -3934,12 +3951,15 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers; - // when --url in command line, teleport to location - const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; - int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY); QString addressLookupString; - if (urlIndex != -1) { - QUrl url(arguments().value(urlIndex + 1)); + + // when --url in command line, teleport to location + QCommandLineParser parser; + QCommandLineOption urlOption("url", "", "value"); + parser.addOption(urlOption); + parser.parse(arguments()); + if (parser.isSet(urlOption)) { + QUrl url = QUrl(parser.value(urlOption)); if (url.scheme() == URL_SCHEME_HIFIAPP) { Setting::Handle("startUpApp").set(url.path()); } else { @@ -4065,7 +4085,7 @@ std::map Application::prepareServerlessDomainContents(QUrl dom bool success = tmpTree->readFromByteArray(domainURL.toString(), data); if (success) { tmpTree->reaverageOctreeElements(); - tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0); + tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), "domain", 0, 0, 0); } std::map namedPaths = tmpTree->getNamedPaths(); @@ -5537,7 +5557,7 @@ bool Application::importEntities(const QString& urlOrFilename, const bool isObse // FIXME: readFromURL() can take over the main event loop which may cause problems, especially if downloading the JSON // from the Web. - success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId); + success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId, true); if (success) { _entityClipboard->reaverageOctreeElements(); } @@ -5545,8 +5565,8 @@ bool Application::importEntities(const QString& urlOrFilename, const bool isObse return success; } -QVector Application::pasteEntities(float x, float y, float z) { - return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z); +QVector Application::pasteEntities(const QString& entityHostType, float x, float y, float z) { + return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), entityHostType, x, y, z); } void Application::init() { @@ -7061,19 +7081,23 @@ void Application::updateWindowTitle() const { auto nodeList = DependencyManager::get(); auto accountManager = DependencyManager::get(); + auto domainAccountManager = DependencyManager::get(); auto isInErrorState = nodeList->getDomainHandler().isInErrorState(); + bool isMetaverseLoggedIn = accountManager->isLoggedIn(); + bool isDomainLoggedIn = domainAccountManager->isLoggedIn(); + QString authedDomain = domainAccountManager->getAuthedDomain(); QString buildVersion = " - Vircadia - " + (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build")) + " " + applicationVersion(); - QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)"; - QString connectionStatus = isInErrorState ? " (ERROR CONNECTING)" : nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED)"; - QString username = accountManager->getAccountInfo().getUsername(); - setCrashAnnotation("sentry[user][username]", username.toStdString()); + QString metaverseUsername = accountManager->getAccountInfo().getUsername(); + QString domainUsername = domainAccountManager->getUsername(); + + setCrashAnnotation("sentry[user][username]", metaverseUsername.toStdString()); QString currentPlaceName; if (isServerlessMode()) { @@ -7089,8 +7113,22 @@ void Application::updateWindowTitle() const { } } - QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) - + currentPlaceName + connectionStatus + loginStatus + buildVersion; + QString metaverseDetails; + if (isMetaverseLoggedIn) { + metaverseDetails = "Metaverse: Logged in as " + metaverseUsername; + } else { + metaverseDetails = "Metaverse: Not Logged In"; + } + + QString domainDetails; + if (currentPlaceName == authedDomain && isDomainLoggedIn) { + domainDetails = "Domain: Logged in as " + domainUsername; + } else { + domainDetails = "Domain: Not Logged In"; + } + + QString title = QString() + currentPlaceName + connectionStatus + " (" + metaverseDetails + ") (" + domainDetails + ")" + + buildVersion; #ifndef WIN32 // crashes with vs2013/win32 @@ -7650,7 +7688,7 @@ bool Application::askToWearAvatarAttachmentUrl(const QString& url) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(url); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); QNetworkReply* reply = networkAccessManager.get(networkRequest); int requestNumber = ++_avatarAttachmentRequest; connect(reply, &QNetworkReply::finished, [this, reply, url, requestNumber]() { diff --git a/interface/src/Application.h b/interface/src/Application.h index 684ff6bdaa..f42696cda0 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -375,7 +375,7 @@ signals: void awayStateWhenFocusLostInVRChanged(bool enabled); public slots: - QVector pasteEntities(float x, float y, float z); + QVector pasteEntities(const QString& entityHostType, float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset = nullptr); bool exportEntities(const QString& filename, float x, float y, float z, float scale); bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1); @@ -425,6 +425,7 @@ public slots: #endif static void showHelp(); + static void gotoTutorial(); void cycleCamera(); void cameraModeChanged(); @@ -732,6 +733,7 @@ private: GraphicsEngine _graphicsEngine; void updateRenderArgs(float deltaTime); + bool _disableLoginScreen { true }; Overlays _overlays; ApplicationOverlay _applicationOverlay; diff --git a/interface/src/ConnectionMonitor.cpp b/interface/src/ConnectionMonitor.cpp index 33d9fddc1b..070015f05b 100644 --- a/interface/src/ConnectionMonitor.cpp +++ b/interface/src/ConnectionMonitor.cpp @@ -14,8 +14,10 @@ #include "Application.h" #include "ui/DialogsManager.h" +#include #include #include +#include #include #include @@ -34,6 +36,10 @@ void ConnectionMonitor::init() { connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ConnectionMonitor::stopTimer); connect(&domainHandler, &DomainHandler::redirectToErrorDomainURL, this, &ConnectionMonitor::stopTimer); connect(this, &ConnectionMonitor::setRedirectErrorState, &domainHandler, &DomainHandler::setRedirectErrorState); + auto accountManager = DependencyManager::get(); + connect(accountManager.data(), &AccountManager::loginComplete, this, &ConnectionMonitor::startTimer); + auto domainAccountManager = DependencyManager::get(); + connect(domainAccountManager.data(), &DomainAccountManager::loginComplete, this, &ConnectionMonitor::startTimer); _timer.setSingleShot(true); if (!domainHandler.isConnected()) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a1bb670837..64cdf98239 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -9,6 +9,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// For happ(ier) development of QML, use these two things: +// This forces QML files to be pulled from the source as you edit it: set environment variable HIFI_USE_SOURCE_TREE_RESOURCES=1 +// Use this to live reload: DependencyManager::get()->clearCache(); + #include "Menu.h" #include #include @@ -84,6 +88,13 @@ Menu::Menu() { dialogsManager.data(), &DialogsManager::toggleLoginDialog); } + auto domainLogin = addActionToQMenuAndActionHash(fileMenu, "Domain: Log In"); + connect(domainLogin, &QAction::triggered, [] { + auto dialogsManager = DependencyManager::get(); + dialogsManager->setDomainLoginState(); + dialogsManager->showDomainLoginDialog(); + }); + // File > Quit addActionToQMenuAndActionHash(fileMenu, MenuOption::Quit, Qt::CTRL | Qt::Key_Q, qApp, SLOT(quit()), QAction::QuitRole); @@ -816,6 +827,8 @@ Menu::Menu() { addActionToQMenuAndActionHash(helpMenu, "Controls Reference", 0, qApp, SLOT(showHelp())); + addActionToQMenuAndActionHash(helpMenu, "Tutorial", 0, qApp, SLOT(gotoTutorial())); + helpMenu->addSeparator(); // Help > Release Notes diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index db74b34d91..c145d40549 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -24,7 +24,7 @@ #include "ModelPropertiesDialog.h" #include "InterfaceLogging.h" -static const int MAX_TEXTURE_SIZE = 1024; +static const int MAX_TEXTURE_SIZE = 8192; void copyDirectoryContent(QDir& from, QDir& to) { for (auto entry : from.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | diff --git a/interface/src/PerformanceManager.cpp b/interface/src/PerformanceManager.cpp index a7b9eff7cc..47e4f0612b 100644 --- a/interface/src/PerformanceManager.cpp +++ b/interface/src/PerformanceManager.cpp @@ -27,7 +27,7 @@ void PerformanceManager::setupPerformancePresetSettings(bool evaluatePlatformTie // If evaluatePlatformTier, evalute the Platform Tier and assign the matching Performance profile by default. // A bunch of Performance, Simulation and Render settings will be set to a matching default value from this - // Here is the mapping between pelatformTIer and performance profile + // Here is the mapping between platformTier and performance profile const std::array platformToPerformancePresetMap = { { PerformanceManager::PerformancePreset::MID, // platform::Profiler::UNKNOWN PerformanceManager::PerformancePreset::LOW, // platform::Profiler::LOW diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 98008583a4..3140c68f88 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -722,7 +722,7 @@ public: * @function MyAvatar.restoreHandAnimation * @param isLeft {boolean} Set to true if using the left hand * @example Override left hand animation for three seconds. - * var ANIM_URL = "https://apidocs.projectathena.dev/models/ClapHands_Standing.fbx"; + * var ANIM_URL = "https://apidocs.vircadia.dev/models/ClapHands_Standing.fbx"; * MyAvatar.overrideHandAnimation(isLeft, ANIM_URL, 30, true, 0, 53); * Script.setTimeout(function () { * MyAvatar.restoreHandAnimation(); @@ -780,7 +780,7 @@ public: * hanging at its sides when it is not moving, the avatar will stand and clap its hands. Note that just as it did before, as soon as the avatar * starts to move, the animation will smoothly blend into the walk animation used by the "walkFwd" animation role. * // An animation of the avatar clapping its hands while standing. Restore default after 30s. - * var ANIM_URL = "https://apidocs.projectathena.dev/models/ClapHands_Standing.fbx"; + * var ANIM_URL = "https://apidocs.vircadia.dev/models/ClapHands_Standing.fbx"; * MyAvatar.overrideRoleAnimation("idleStand", ANIM_URL, 30, true, 0, 53); * Script.setTimeout(function () { * MyAvatar.restoreRoleAnimation(); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 3a25721528..997dcfe685 100755 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -407,13 +407,13 @@ void MyCharacterController::clearDetailedMotionStates() { } void MyCharacterController::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) { - for (size_t i = 0; i < _detailedMotionStates.size(); i++) { - _detailedMotionStates[i]->forceActive(); + for (auto& detailedMotionState : _detailedMotionStates) { + detailedMotionState->forceActive(); } if (_pendingFlags & PENDING_FLAG_REMOVE_DETAILED_FROM_SIMULATION) { _pendingFlags &= ~PENDING_FLAG_REMOVE_DETAILED_FROM_SIMULATION; - for (size_t i = 0; i < _detailedMotionStates.size(); i++) { - transaction.objectsToRemove.push_back(_detailedMotionStates[i]); + for (auto& detailedMotionState : _detailedMotionStates) { + transaction.objectsToRemove.push_back(detailedMotionState); } // NOTE: the DetailedMotionStates are deleted after being added to PhysicsEngine::Transaction::_objectsToRemove // See AvatarManager::handleProcessedPhysicsTransaction() diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index aa6c074d08..ae453d5b00 100755 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -116,10 +116,10 @@ void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const { int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) { int32_t bytesRead = Avatar::parseDataFromBuffer(buffer); - for (size_t i = 0; i < _detailedMotionStates.size(); i++) { + for (auto& detailedMotionState : _detailedMotionStates) { // NOTE: we activate _detailedMotionStates is because they are KINEMATIC // and Bullet will automagically call DetailedMotionState::getWorldTransform() when active. - _detailedMotionStates[i]->forceActive(); + detailedMotionState->forceActive(); } if (_moving && _motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index c0a6b64421..af7ac8165b 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -60,10 +60,11 @@ bool ClipboardScriptingInterface::importEntities( return retVal; } -QVector ClipboardScriptingInterface::pasteEntities(glm::vec3 position) { +QVector ClipboardScriptingInterface::pasteEntities(glm::vec3 position, const QString& entityHostType) { QVector retVal; BLOCKING_INVOKE_METHOD(qApp, "pasteEntities", Q_RETURN_ARG(QVector, retVal), + Q_ARG(const QString&, entityHostType), Q_ARG(float, position.x), Q_ARG(float, position.y), Q_ARG(float, position.z)); diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 9e72d9ea15..9660b2158b 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -117,10 +117,11 @@ public: * Pastes the contents of the clipboard into the domain. * @function Clipboard.pasteEntities * @param {Vec3} position - The position to paste the clipboard contents at. + * @param {Entities.EntityHostType} [entityHostType="domain"] - The type of entities to create. * @returns {Uuid[]} The IDs of the new entities that were created as a result of the paste operation. If entities couldn't * be created then an empty array is returned. */ - Q_INVOKABLE QVector pasteEntities(glm::vec3 position); + Q_INVOKABLE QVector pasteEntities(glm::vec3 position, const QString& entityHostType = "domain"); }; #endif // hifi_ClipboardScriptingInterface_h diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index f4aa36e2f4..434adf0bc8 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -29,6 +29,7 @@ #include "Menu.h" #include "OffscreenUi.h" #include "commerce/QmlCommerce.h" +#include "NetworkingConstants.h" static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); static const QString LAST_BROWSE_LOCATION_SETTING = "LastBrowseLocation"; @@ -411,6 +412,10 @@ QString WindowScriptingInterface::checkVersion() { return QCoreApplication::applicationVersion(); } +QString WindowScriptingInterface::getUserAgent() { + return NetworkingConstants::VIRCADIA_USER_AGENT; +} + QString WindowScriptingInterface::protocolSignature() { return protocolVersionsSignatureBase64(); } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 0c2fdd1614..28a725f3cb 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -295,6 +295,13 @@ public slots: */ QString checkVersion(); + /**jsdoc + * Gets Interface's user agent. + * @function Window.getUserAgent + * @returns {string} Interface's user agent. + */ + QString getUserAgent(); + /**jsdoc * Gets the signature for Interface's protocol version. * @function Window.protocolSignature diff --git a/interface/src/ui/DialogsManager.cpp b/interface/src/ui/DialogsManager.cpp index 0a655de5e5..8c8e3bc3c3 100644 --- a/interface/src/ui/DialogsManager.cpp +++ b/interface/src/ui/DialogsManager.cpp @@ -4,6 +4,7 @@ // // Created by Clement on 1/18/15. // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -109,11 +110,34 @@ void DialogsManager::setDomainConnectionFailureVisibility(bool visible) { } } +void DialogsManager::setMetaverseLoginState() { + // We're only turning off the domain login trigger but the actual domain auth URL is still saved. + // So we can continue the domain login if desired. + _isDomainLogin = false; +} + +void DialogsManager::setDomainLoginState() { + _isDomainLogin = true; +} + +void DialogsManager::setDomainLogin(bool isDomainLogin, const QString& domain) { + _isDomainLogin = isDomainLogin; + if (!domain.isEmpty()) { + _domainLoginDomain = domain; + } +} + void DialogsManager::toggleLoginDialog() { + setDomainLogin(false); LoginDialog::toggleAction(); } void DialogsManager::showLoginDialog() { + + // ####### TODO: May be called from script via DialogsManagerScriptingInterface. Need to handle the case that it's already + // displayed and may be the domain login version. + + setDomainLogin(false); LoginDialog::showWithSelection(); } @@ -121,10 +145,22 @@ void DialogsManager::hideLoginDialog() { LoginDialog::hide(); } + +void DialogsManager::showDomainLoginDialog(const QString& domain) { + setDomainLogin(true, domain); + LoginDialog::showWithSelection(); +} + +// #######: TODO: Domain version of toggleLoginDialog()? + +// #######: TODO: Domain version of hideLoginDialog()? + + void DialogsManager::showUpdateDialog() { UpdateDialog::show(); } + void DialogsManager::octreeStatsDetails() { if (!_octreeStatsDialog) { _octreeStatsDialog = new OctreeStatsDialog(qApp->getWindow(), qApp->getOcteeSceneStats()); diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 949c86c240..864174296e 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -4,6 +4,7 @@ // // Created by Clement on 1/18/15. // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -40,6 +41,10 @@ public: QPointer getTestingDialog() const { return _testingDialog; } void emitAddressBarShown(bool visible) { emit addressBarShown(visible); } void setAddressBarVisible(bool addressBarVisible); + void setMetaverseLoginState(); + void setDomainLoginState(); + bool getIsDomainLogin() { return _isDomainLogin; } + QString getDomainLoginDomain() { return _domainLoginDomain; } public slots: void showAddressBar(); @@ -49,6 +54,7 @@ public slots: void toggleLoginDialog(); void showLoginDialog(); void hideLoginDialog(); + void showDomainLoginDialog(const QString& domain = ""); void octreeStatsDetails(); void lodTools(); void hmdTools(bool showTools); @@ -82,6 +88,10 @@ private: QPointer _domainConnectionDialog; bool _dialogCreatedWhileShown { false }; bool _addressBarVisible { false }; + + void setDomainLogin(bool isDomainLogin, const QString& domain = ""); + bool _isDomainLogin { false }; + QString _domainLoginDomain; }; #endif // hifi_DialogsManager_h diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index c0e96fe8bb..b45a62ae3a 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -4,6 +4,7 @@ // // Created by Bradley Austin Davis on 2015/04/14 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -24,7 +25,9 @@ #include #include "AccountManager.h" +#include "DomainAccountManager.h" #include "DependencyManager.h" +#include "DialogsManager.h" #include "Menu.h" #include "Application.h" @@ -38,12 +41,17 @@ const QUrl LOGIN_DIALOG = PathUtils::qmlUrl("OverlayLoginDialog.qml"); LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent) { auto accountManager = DependencyManager::get(); + auto domainAccountManager = DependencyManager::get(); // the login hasn't been dismissed yet if the user isn't logged in and is encouraged to login. #if !defined(Q_OS_ANDROID) connect(accountManager.data(), &AccountManager::loginComplete, this, &LoginDialog::handleLoginCompleted); connect(accountManager.data(), &AccountManager::loginFailed, this, &LoginDialog::handleLoginFailed); + connect(domainAccountManager.data(), &DomainAccountManager::loginComplete, + this, &LoginDialog::handleLoginCompleted); + connect(domainAccountManager.data(), &DomainAccountManager::loginFailed, + this, &LoginDialog::handleLoginFailed); connect(qApp, &Application::loginDialogFocusEnabled, this, &LoginDialog::focusEnabled); connect(qApp, &Application::loginDialogFocusDisabled, this, &LoginDialog::focusDisabled); connect(this, SIGNAL(dismissedLoginDialog()), qApp, SLOT(onDismissedLoginDialog())); @@ -91,14 +99,16 @@ void LoginDialog::toggleAction() { if (accountManager->isLoggedIn()) { // change the menu item to logout - loginAction->setText("Logout " + accountManager->getAccountInfo().getUsername()); + loginAction->setText("Metaverse: Logout " + accountManager->getAccountInfo().getUsername()); connection = connect(loginAction, &QAction::triggered, accountManager.data(), &AccountManager::logout); } else { // change the menu item to login - loginAction->setText("Log In / Sign Up"); + loginAction->setText("Metaverse: Log In / Sign Up"); connection = connect(loginAction, &QAction::triggered, [] { // if not in login state, show. if (!qApp->getLoginDialogPoppedUp()) { + auto dialogsManager = DependencyManager::get(); + dialogsManager->setMetaverseLoginState(); LoginDialog::showWithSelection(); } }); @@ -131,10 +141,15 @@ void LoginDialog::dismissLoginDialog() { } void LoginDialog::login(const QString& username, const QString& password) const { - qDebug() << "Attempting to login " << username; + qDebug() << "Attempting to login" << username; DependencyManager::get()->requestAccessToken(username, password); } +void LoginDialog::loginDomain(const QString& username, const QString& password) const { + qDebug() << "Attempting to login" << username << "into a domain"; + DependencyManager::get()->requestAccessToken(username, password); +} + void LoginDialog::loginThroughOculus() { qDebug() << "Attempting to login through Oculus"; if (auto oculusPlatformPlugin = PluginManager::getInstance()->getOculusPlatformPlugin()) { @@ -410,3 +425,11 @@ void LoginDialog::signupFailed(QNetworkReply* reply) { emit handleSignupFailed(DEFAULT_SIGN_UP_FAILURE_MESSAGE); } } + +bool LoginDialog::getDomainLoginRequested() const { + return DependencyManager::get()->getIsDomainLogin(); +} + +QString LoginDialog::getDomainLoginDomain() const { + return DependencyManager::get()->getDomainLoginDomain(); +} diff --git a/interface/src/ui/LoginDialog.h b/interface/src/ui/LoginDialog.h index 7c659a9320..9f4af5debb 100644 --- a/interface/src/ui/LoginDialog.h +++ b/interface/src/ui/LoginDialog.h @@ -4,6 +4,7 @@ // // Created by Bradley Austin Davis on 2015/04/14 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -71,6 +72,7 @@ protected slots: Q_INVOKABLE QString oculusUserID() const; Q_INVOKABLE void login(const QString& username, const QString& password) const; + Q_INVOKABLE void loginDomain(const QString& username, const QString& password) const; Q_INVOKABLE void loginThroughSteam(); Q_INVOKABLE void linkSteam(); Q_INVOKABLE void createAccountFromSteam(QString username = QString()); @@ -81,6 +83,10 @@ protected slots: Q_INVOKABLE void signup(const QString& email, const QString& username, const QString& password); Q_INVOKABLE bool getLoginDialogPoppedUp() const; + + Q_INVOKABLE bool getDomainLoginRequested() const; + Q_INVOKABLE QString getDomainLoginDomain() const; + }; #endif // hifi_LoginDialog_h diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 4709cc0a9c..96c10be212 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -27,6 +27,7 @@ #include #include +#include #include const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "skeletons", "attachments" }; @@ -225,7 +226,7 @@ void ModelHandler::update() { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); QNetworkReply* reply = networkAccessManager.head(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); } @@ -278,7 +279,7 @@ void ModelHandler::queryNewFiles(QString marker) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); QNetworkReply* reply = networkAccessManager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt index a25aec37a7..50f0cbc16f 100644 --- a/launchers/darwin/CMakeLists.txt +++ b/launchers/darwin/CMakeLists.txt @@ -143,13 +143,13 @@ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}) include(CPackComponent) set(CPACK_PACKAGE_NAME "HQ Launcher") -set(CPACK_PACKAGE_VENDOR "High Fidelity") +set(CPACK_PACKAGE_VENDOR "Vircadia") set(CPACK_PACKAGE_VERSION ${BUILD_VERSION}) set(CPACK_PACKAGE_FILE_NAME "HQ Launcher") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) -set(DMG_SUBFOLDER_NAME "High Fidelity") +set(DMG_SUBFOLDER_NAME "Vircadia") set(ESCAPED_DMG_SUBFOLDER_NAME "") set(DMG_SUBFOLDER_ICON "${CMAKE_SOURCE_DIR}/cmake/installer/install-folder.rsrc") diff --git a/launchers/qt/CMakeLists.txt b/launchers/qt/CMakeLists.txt index 596f3b7d5c..400615be90 100644 --- a/launchers/qt/CMakeLists.txt +++ b/launchers/qt/CMakeLists.txt @@ -276,12 +276,12 @@ if (APPLE) include(CPackComponent) set(CPACK_PACKAGE_NAME "HQ Launcher") - set(CPACK_PACKAGE_VENDOR "High Fidelity") + set(CPACK_PACKAGE_VENDOR "Vircadia") set(CPACK_PACKAGE_FILE_NAME "HQ Launcher") set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) - set(DMG_SUBFOLDER_NAME "High Fidelity") + set(DMG_SUBFOLDER_NAME "Vircadia") set(ESCAPED_DMG_SUBFOLDER_NAME "") set(DMG_SUBFOLDER_ICON "${CMAKE_SOURCE_DIR}/cmake/installer/install-folder.rsrc") diff --git a/launchers/qt/resources/qml/HFControls/HFTextLogo.qml b/launchers/qt/resources/qml/HFControls/HFTextLogo.qml index b8d06f16f1..f377c9a34d 100644 --- a/launchers/qt/resources/qml/HFControls/HFTextLogo.qml +++ b/launchers/qt/resources/qml/HFControls/HFTextLogo.qml @@ -2,7 +2,7 @@ import QtQuick 2.3 import QtQuick 2.1 Text { - text: "High Fidelity" + text: "Vircadia" font.bold: true font.family: "Graphik Semibold" font.pixelSize: 17 diff --git a/launchers/qt/src/Launcher.cpp b/launchers/qt/src/Launcher.cpp index 7522529ff9..bd54619487 100644 --- a/launchers/qt/src/Launcher.cpp +++ b/launchers/qt/src/Launcher.cpp @@ -21,7 +21,7 @@ Launcher::Launcher(int& argc, char**argv) : QGuiApplication(argc, argv) { _launcherWindow->rootContext()->setContextProperty("LauncherState", _launcherState.get()); _launcherWindow->rootContext()->setContextProperty("PathUtils", new PathUtils()); _launcherWindow->rootContext()->setContextProperty("Platform", platform); - _launcherWindow->setTitle("High Fidelity"); + _launcherWindow->setTitle("Vircadia"); _launcherWindow->setFlags(Qt::FramelessWindowHint | Qt::Window); _launcherWindow->setLauncherStatePtr(_launcherState); diff --git a/launchers/qt/src/LauncherInstaller_windows.cpp b/launchers/qt/src/LauncherInstaller_windows.cpp index b5558f972c..cf5b2b501f 100644 --- a/launchers/qt/src/LauncherInstaller_windows.cpp +++ b/launchers/qt/src/LauncherInstaller_windows.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include @@ -253,7 +253,7 @@ void LauncherInstaller::createApplicationRegistryKeys() { success = insertRegistryKey(REGISTRY_PATH, "UninstallString", uninstallPath); success = insertRegistryKey(REGISTRY_PATH, "DisplayVersion", std::string(LAUNCHER_BUILD_VERSION)); success = insertRegistryKey(REGISTRY_PATH, "DisplayIcon", applicationExe); - success = insertRegistryKey(REGISTRY_PATH, "Publisher", "High Fidelity"); + success = insertRegistryKey(REGISTRY_PATH, "Publisher", "Vircadia"); auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); diff --git a/launchers/qt/src/main.cpp b/launchers/qt/src/main.cpp index 75c35cd708..c9ce0caeb1 100644 --- a/launchers/qt/src/main.cpp +++ b/launchers/qt/src/main.cpp @@ -31,7 +31,7 @@ bool hasSuffix(const std::string& path, const std::string& suffix) { int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setOrganizationName("High Fidelity"); + QCoreApplication::setOrganizationName("Vircadia"); QCoreApplication::setApplicationName("HQ Launcher"); Q_INIT_RESOURCE(resources); diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 60bcb0f004..6dfdc46c6f 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -310,7 +310,7 @@ BOOL LauncherManager::getAndCreatePaths(PathType type, CString& outPath) { outPath += DIRECTORY_NAME_INTERFACE; } else if (type == PathType::Content_Directory) { outPath += DIRECTORY_NAME_CONTENT; - } + } return (CreateDirectory(outPath, NULL) || ERROR_ALREADY_EXISTS == GetLastError()); } } @@ -377,7 +377,7 @@ BOOL LauncherManager::createConfigJSON() { return TRUE; } -LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, +LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn, CString& organizationBuildTag) { CString configPath; getAndCreatePaths(PathType::Interface_Directory, configPath); @@ -388,7 +388,7 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C } Json::Value config; configFile >> config; - if (config["version"].isString() && + if (config["version"].isString() && config["domain"].isString() && config["content"].isString()) { loggedIn = config["loggedIn"].asBool(); @@ -446,7 +446,7 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString CString url = _T("/organizations/") + hash + _T(".json"); LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(), true, L"orgs.highfidelity.com", url, - contentTypeJson, CStringA(), + contentTypeJson, CStringA(), response, false); if (error != LauncherUtils::ResponseError::NoError) { return error; @@ -557,7 +557,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch addToLog(_T("Already running most recent build. Launching interface.exe")); } else { addToLog(_T("Updating the launcher was not allowed --noUpdate")); - } + } if (isInstalled) { addToLog(_T("Installed version: ") + currentVersion); if (!newInterfaceVersion) { @@ -576,7 +576,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch } } _shouldWait = FALSE; - + } else { setFailed(true); CString msg; @@ -587,7 +587,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch } } -LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, +LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, const CString& password) { CStringA post = "grant_type=password&username="; post += username; @@ -599,9 +599,9 @@ LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString response; LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(), true, - L"metaverse.highfidelity.com", + L"metaverse.highfidelity.com", L"/oauth/token", - contentTypeText, post, + contentTypeText, post, response, true); if (error != LauncherUtils::ResponseError::NoError) { return error; @@ -629,7 +629,7 @@ BOOL LauncherManager::createApplicationRegistryKeys(int size) { success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "UninstallString", uninstallPath); success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayVersion", LauncherUtils::cStringToStd(_latestVersion)); success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayIcon", applicationExe); - success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "Publisher", "High Fidelity"); + success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "Publisher", "Vircadia"); success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "InstallDate", LauncherUtils::cStringToStd(CTime::GetCurrentTime().Format("%Y%m%d"))); success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "EstimatedSize", (DWORD)size); success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "NoModify", (DWORD)1); @@ -686,9 +686,9 @@ BOOL LauncherManager::extractApplication() { updateProgress(ProcessType::UnzipApplication, max(progress, 0.0f)); }; _currentProcess = ProcessType::UnzipApplication; - BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipApplication, + BOOL success = LauncherUtils::unzipFileOnThread(ProcessType::UnzipApplication, LauncherUtils::cStringToStd(_applicationZipPath), - LauncherUtils::cStringToStd(installPath), + LauncherUtils::cStringToStd(installPath), onExtractFinished, onProgress); if (success) { addToLog(_T("Created thread for unzipping application.")); @@ -737,7 +737,7 @@ void LauncherManager::restartNewLauncher() { continueAction = ContinueActionOnStart::ContinueUpdate; } else if (_keepLoggingIn) { continueAction = ContinueActionOnStart::ContinueLogIn; - } + } CStringW params; params.Format(_T(" --restart --noUpdate --continueAction %s"), getContinueActionParam(continueAction)); LauncherUtils::launchApplication(_tempLauncherPath, params.GetBuffer()); diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index 621323575f..2fd52ee036 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -26,6 +26,9 @@ static const int MAX_TARGET_MARKERS = 30; static const float JOINT_CHAIN_INTERP_TIME = 0.5f; +static QTime debounceJointWarningsClock; +static const int JOINT_WARNING_DEBOUNCE_TIME = 30000; // 30 seconds + static void lookupJointInfo(const AnimInverseKinematics::JointChainInfo& jointChainInfo, int indexA, int indexB, const AnimInverseKinematics::JointInfo** jointInfoA, @@ -91,6 +94,7 @@ AnimInverseKinematics::IKTargetVar::IKTargetVar(const IKTargetVar& orig) : } AnimInverseKinematics::AnimInverseKinematics(const QString& id) : AnimNode(AnimNode::Type::InverseKinematics, id) { + debounceJointWarningsClock.start(); } AnimInverseKinematics::~AnimInverseKinematics() { @@ -158,6 +162,14 @@ void AnimInverseKinematics::setTargetVars(const QString& jointName, const QStrin } } +bool debounceJointWarnings() { + if (debounceJointWarningsClock.elapsed() >= JOINT_WARNING_DEBOUNCE_TIME) { + debounceJointWarningsClock.restart(); + return true; + } + return false; +} + void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std::vector& targets, const AnimPoseVec& underPoses) { _hipsTargetIndex = -1; @@ -172,7 +184,7 @@ void AnimInverseKinematics::computeTargets(const AnimVariantMap& animVars, std:: if (jointIndex >= 0) { // this targetVar has a valid joint --> cache the indices targetVar.jointIndex = jointIndex; - } else { + } else if (debounceJointWarnings()) { qCWarning(animation) << "AnimInverseKinematics could not find jointName" << targetVar.jointName << "in skeleton"; } } diff --git a/libraries/auto-updater/src/AutoUpdater.cpp b/libraries/auto-updater/src/AutoUpdater.cpp index d8afac59b2..e00ae6dafc 100644 --- a/libraries/auto-updater/src/AutoUpdater.cpp +++ b/libraries/auto-updater/src/AutoUpdater.cpp @@ -51,7 +51,7 @@ void AutoUpdater::getLatestVersionData() { QNetworkRequest latestVersionRequest(buildsURL); latestVersionRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + latestVersionRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); QNetworkReply* reply = networkAccessManager.get(latestVersionRequest); connect(reply, &QNetworkReply::finished, this, &AutoUpdater::parseLatestVersionData); } diff --git a/libraries/baking/src/JSBaker.cpp b/libraries/baking/src/JSBaker.cpp index 96d7247a82..def217f8fd 100644 --- a/libraries/baking/src/JSBaker.cpp +++ b/libraries/baking/src/JSBaker.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -62,7 +63,7 @@ void JSBaker::loadScript() { // setup the request to follow re-directs and always hit the network networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); networkRequest.setUrl(_jsURL); diff --git a/libraries/baking/src/ModelBaker.cpp b/libraries/baking/src/ModelBaker.cpp index 70290fe283..1b81ee9740 100644 --- a/libraries/baking/src/ModelBaker.cpp +++ b/libraries/baking/src/ModelBaker.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -159,7 +160,7 @@ void ModelBaker::saveSourceModel() { // setup the request to follow re-directs and always hit the network networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); networkRequest.setUrl(_modelURL); diff --git a/libraries/baking/src/TextureBaker.cpp b/libraries/baking/src/TextureBaker.cpp index 182caf7fc6..d70c6586b7 100644 --- a/libraries/baking/src/TextureBaker.cpp +++ b/libraries/baking/src/TextureBaker.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -99,7 +100,7 @@ void TextureBaker::loadTexture() { // setup the request to follow re-directs and always hit the network networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); networkRequest.setUrl(_textureURL); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index fb2cf01580..eb7856b7ed 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1337,7 +1337,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _model->setCullWithParent(_cullWithParent); _model->setRenderWithZones(_renderWithZones); emit requestRenderUpdate(); - if(didVisualGeometryRequestSucceed) { + if (didVisualGeometryRequestSucceed) { emit DependencyManager::get()-> modelAddedToScene(entity->getEntityItemID(), NestableType::Entity, _model); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f34eb85230..bc56781924 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -199,7 +199,7 @@ float importanceSample3DDimension(float startDim) { return dimension; } -ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, +ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createParticle(const Transform& baseTransform, const particle::Properties& particleProperties, const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, const TriangleInfo& triangleInfo) { CpuParticle particle; @@ -217,7 +217,7 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa const auto& polarFinish = particleProperties.polar.finish; particle.seed = randFloatInRange(-1.0f, 1.0f); - particle.expiration = now + (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND); + particle.expiration = (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND); particle.relativePosition = glm::vec3(0.0f); particle.basePosition = baseTransform.getTranslation(); @@ -403,7 +403,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { computeTriangles(geometryResource->getHFMModel()); } // emit particle - _cpuParticles.push_back(createParticle(now, modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo)); + _cpuParticles.push_back(createParticle(modelTransform, particleProperties, shapeType, geometryResource, _triangleInfo)); _timeUntilNextEmit = emitInterval; if (emitInterval < timeRemaining) { timeRemaining -= emitInterval; @@ -415,7 +415,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { } // Kill any particles that have expired or are over the max size - while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration <= now)) { + while (_cpuParticles.size() > particleProperties.maxParticles || (!_cpuParticles.empty() && _cpuParticles.front().expiration == 0)) { _cpuParticles.pop_front(); } @@ -428,6 +428,7 @@ void ParticleEffectEntityRenderer::stepSimulation() { } particle.basePosition = modelTransform.getTranslation(); } + particle.expiration = particle.expiration >= interval ? particle.expiration - interval : 0; particle.integrate(deltaTime); } _prevEmitterShouldTrail = particleProperties.emission.shouldTrail; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index cc907f2b1d..8a3d8120f5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -88,7 +88,7 @@ private: glm::mat4 transform; } _triangleInfo; - static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties, + static CpuParticle createParticle(const Transform& baseTransform, const particle::Properties& particleProperties, const ShapeType& shapeType, const GeometryResource::Pointer& geometryResource, const TriangleInfo& triangleInfo); void stepSimulation(); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index 5bc61606ad..e4d6d099a6 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -45,7 +45,7 @@ private: PulsePropertyGroup _pulseProperties; std::shared_ptr _material { std::make_shared() }; glm::vec3 _color { NAN }; - float _alpha; + float _alpha { NAN }; glm::vec3 _position; glm::vec3 _dimensions; diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index e0f14b47e7..dae0922f4a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -2399,7 +2399,9 @@ signals: /**jsdoc - * Triggered when an avatar enters an entity, but only if the entity has an entity method exposed for this event. + * Triggered when an avatar enters an entity. + * Note: At the initial loading of the script, if the avatar is already present inside the entity, it might be too late + * to catch this event when the script runs, so it won't trigger. The {@link Entities.preload|preload} signal can be used to handle those cases. *

See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.

* @function Entities.enterEntity * @param {Uuid} entityID - The ID of the entity that the avatar entered. @@ -2408,7 +2410,7 @@ signals: void enterEntity(const EntityItemID& entityItemID); /**jsdoc - * Triggered when an avatar leaves an entity, but only if the entity has an entity method exposed for this event. + * Triggered when an avatar leaves an entity. *

See also, {@link Entities|Entity Methods} and {@link Script.addEventHandler}.

* @function Entities.leaveEntity * @param {Uuid} entityID - The ID of the entity that the avatar left. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1ce19033e5..e6f5e36202 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -537,7 +537,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti return true; } -EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone) { +EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone, const bool isImport) { EntityItemProperties props = properties; auto nodeList = DependencyManager::get(); @@ -548,7 +548,8 @@ EntityItemPointer EntityTree::addEntity(const EntityItemID& entityID, const Enti if (properties.getEntityHostType() == entity::HostType::DOMAIN && getIsClient() && !nodeList->getThisNodeCanRez() && !nodeList->getThisNodeCanRezTmp() && - !nodeList->getThisNodeCanRezCertified() && !nodeList->getThisNodeCanRezTmpCertified() && !_serverlessDomain && !isClone) { + !nodeList->getThisNodeCanRezCertified() && !nodeList->getThisNodeCanRezTmpCertified() && + !_serverlessDomain && !isClone && !isImport) { return nullptr; } @@ -2233,15 +2234,24 @@ void EntityTree::fixupNeedsParentFixups() { } entity->postParentFixup(); - } else if (getIsServer() || _avatarIDs.contains(entity->getParentID())) { - // this is a child of an avatar, which the entity server will never have - // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. - if (!_childrenOfAvatars.contains(entity->getParentID())) { - _childrenOfAvatars[entity->getParentID()] = QSet(); + } else { + bool needsUpdate = getIsServer(); + if (!needsUpdate) { + std::lock_guard lock(_avatarIDsLock); + needsUpdate = _avatarIDs.contains(entity->getParentID()); + } + + if (needsUpdate) { + std::lock_guard lock(_childrenOfAvatarsLock); + // this is a child of an avatar, which the entity server will never have + // a SpatiallyNestable object for. Add it to a list for cleanup when the avatar leaves. + if (!_childrenOfAvatars.contains(entity->getParentID())) { + _childrenOfAvatars[entity->getParentID()] = QSet(); + } + _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); + doMove = true; + iter.remove(); // and pull it out of the list } - _childrenOfAvatars[entity->getParentID()] += entity->getEntityItemID(); - doMove = true; - iter.remove(); // and pull it out of the list } if (queryAACubeSuccess && doMove) { @@ -2261,8 +2271,19 @@ void EntityTree::fixupNeedsParentFixups() { } } -void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) { - QHash>::const_iterator itr = _childrenOfAvatars.constFind(avatarID); +void EntityTree::knowAvatarID(const QUuid& avatarID) { + std::lock_guard lock(_avatarIDsLock); + _avatarIDs += avatarID; +} + +void EntityTree::forgetAvatarID(const QUuid& avatarID) { + std::lock_guard lock(_avatarIDsLock); + _avatarIDs -= avatarID; +} + +void EntityTree::deleteDescendantsOfAvatar(const QUuid& avatarID) { + std::lock_guard lock(_childrenOfAvatarsLock); + auto itr = _childrenOfAvatars.find(avatarID); if (itr != _childrenOfAvatars.end()) { if (!itr.value().empty()) { std::vector ids; @@ -2280,8 +2301,10 @@ void EntityTree::deleteDescendantsOfAvatar(QUuid avatarID) { void EntityTree::removeFromChildrenOfAvatars(EntityItemPointer entity) { QUuid avatarID = entity->getParentID(); - if (_childrenOfAvatars.contains(avatarID)) { - _childrenOfAvatars[avatarID].remove(entity->getID()); + std::lock_guard lock(_childrenOfAvatarsLock); + auto itr = _childrenOfAvatars.find(avatarID); + if (itr != _childrenOfAvatars.end()) { + itr.value().remove(entity->getID()); } } @@ -2657,11 +2680,12 @@ QByteArray EntityTree::remapActionDataIDs(QByteArray actionData, QHash EntityTree::sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, - float x, float y, float z) { + const QString& entityHostType, float x, float y, float z) { SendEntitiesOperationArgs args; args.ourTree = this; args.otherTree = localTree; args.root = glm::vec3(x, y, z); + args.entityHostType = entityHostType; // If this is called repeatedly (e.g., multiple pastes with the same data), the new elements will clash unless we // use new identifiers. We need to keep a map so that we can map parent identifiers correctly. QHash map; @@ -2751,6 +2775,11 @@ bool EntityTree::sendEntitiesOperation(const OctreeElementPointer& element, void EntityItemID newID = getMapped(oldID); EntityItemProperties properties = item->getProperties(); + properties.setEntityHostTypeFromString(args->entityHostType); + if (properties.getEntityHostType() == entity::HostType::AVATAR) { + properties.setOwningAvatarID(AVATAR_SELF_ID); + } + EntityItemID oldParentID = properties.getParentID(); if (oldParentID.isInvalidID()) { // no parent properties.setPosition(properties.getPosition() + args->root); @@ -2764,6 +2793,17 @@ bool EntityTree::sendEntitiesOperation(const OctreeElementPointer& element, void } } + QVector oldRenderWithZones = properties.getRenderWithZones(); + if (!oldRenderWithZones.isEmpty()) { + QVector newRenderWithZones; + for (QUuid oldRenderWithZoneID : oldRenderWithZones) { + if (args->ourTree->findEntityByEntityItemID(oldRenderWithZoneID)) { + newRenderWithZones.append(getMapped(oldRenderWithZoneID)); + } + } + properties.setRenderWithZones(newRenderWithZones); + } + properties.setXNNeighborID(getMapped(properties.getXNNeighborID())); properties.setXPNeighborID(getMapped(properties.getXPNeighborID())); properties.setYNNeighborID(getMapped(properties.getYNNeighborID())); @@ -2926,7 +2966,7 @@ void convertGrabUserDataToProperties(EntityItemProperties& properties) { } -bool EntityTree::readFromMap(QVariantMap& map) { +bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { // These are needed to deal with older content (before adding inheritance modes) int contentVersion = map["Version"].toInt(); @@ -3096,7 +3136,7 @@ bool EntityTree::readFromMap(QVariantMap& map) { } } - EntityItemPointer entity = addEntity(entityItemID, properties); + EntityItemPointer entity = addEntity(entityItemID, properties, isImport); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); success = false; diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 2d5119d626..66e761f7a0 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -40,6 +40,7 @@ public: class SendEntitiesOperationArgs { public: glm::vec3 root; + QString entityHostType; EntityTree* ourTree; EntityTreePointer otherTree; QHash* map; @@ -117,7 +118,7 @@ public: // The newer API... void postAddEntity(EntityItemPointer entityItem); - EntityItemPointer addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone = false); + EntityItemPointer addEntity(const EntityItemID& entityID, const EntityItemProperties& properties, bool isClone = false, const bool isImport = false); // use this method if you only know the entityID bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties, const SharedNodePointer& senderNode = SharedNodePointer(nullptr)); @@ -177,7 +178,7 @@ public: static QByteArray remapActionDataIDs(QByteArray actionData, QHash& map); QVector sendEntities(EntityEditPacketSender* packetSender, EntityTreePointer localTree, - float x, float y, float z); + const QString& entityHostType, float x, float y, float z); void entityChanged(EntityItemPointer entity); @@ -195,7 +196,7 @@ public: virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) override; - virtual bool readFromMap(QVariantMap& entityDescription) override; + virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) override; virtual bool writeToJSON(QString& jsonString, const OctreeElementPointer& element) override; @@ -239,9 +240,9 @@ public: Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name) const; Q_INVOKABLE QStringList getJointNames(const QUuid& entityID) const; - void knowAvatarID(QUuid avatarID) { _avatarIDs += avatarID; } - void forgetAvatarID(QUuid avatarID) { _avatarIDs -= avatarID; } - void deleteDescendantsOfAvatar(QUuid avatarID); + void knowAvatarID(const QUuid& avatarID); + void forgetAvatarID(const QUuid& avatarID); + void deleteDescendantsOfAvatar(const QUuid& avatarID); void removeFromChildrenOfAvatars(EntityItemPointer entity); void addToNeedsParentFixupList(EntityItemPointer entity); @@ -364,8 +365,10 @@ protected: QVector _needsParentFixup; // entites with a parentID but no (yet) known parent instance mutable QReadWriteLock _needsParentFixupLock; + std::mutex _avatarIDsLock; // we maintain a list of avatarIDs to notice when an entity is a child of one. QSet _avatarIDs; // IDs of avatars connected to entity server + std::mutex _childrenOfAvatarsLock; QHash> _childrenOfAvatars; // which entities are children of which avatars float _maxTmpEntityLifetime { DEFAULT_MAX_TMP_ENTITY_LIFETIME }; diff --git a/libraries/fbx/src/FBXSerializer_Mesh.cpp b/libraries/fbx/src/FBXSerializer_Mesh.cpp index 802db4b428..f74a960dc8 100644 --- a/libraries/fbx/src/FBXSerializer_Mesh.cpp +++ b/libraries/fbx/src/FBXSerializer_Mesh.cpp @@ -127,7 +127,7 @@ void appendIndex(MeshData& data, QVector& indices, int index, bool deduplic glm::vec4 color; - bool hasColors = (data.colors.size() > 1); + bool hasColors = (data.colors.size() > 0); if (hasColors) { int colorIndex = data.colorsByVertex ? vertexIndex : index; if (data.colorIndices.isEmpty()) { diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index b647fe2e7f..cd3b8d268c 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -17,6 +17,7 @@ #include #include +#include #include QVariantHash FSTReader::parseMapping(QIODevice* device) { @@ -253,7 +254,7 @@ QVariantHash FSTReader::downloadMapping(const QString& url) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(url); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); QNetworkReply* reply = networkAccessManager.get(networkRequest); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); diff --git a/libraries/fbx/src/GLTFSerializer.cpp b/libraries/fbx/src/GLTFSerializer.cpp index a7af5518a9..8234f2b17d 100755 --- a/libraries/fbx/src/GLTFSerializer.cpp +++ b/libraries/fbx/src/GLTFSerializer.cpp @@ -1055,6 +1055,11 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int indicesAccessorIdx = primitive.indices; + if (indicesAccessorIdx > _file.accessors.size()) { + qWarning(modelformat) << "Indices accessor index is out of bounds for model " << _url; + continue; + } + GLTFAccessor& indicesAccessor = _file.accessors[indicesAccessorIdx]; // Buffers @@ -1093,6 +1098,11 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& foreach(auto &key, keys) { int accessorIdx = primitive.attributes.values[key]; + if (accessorIdx > _file.accessors.size()) { + qWarning(modelformat) << "Accessor index is out of bounds for model " << _url; + continue; + } + GLTFAccessor& accessor = _file.accessors[accessorIdx]; if (key == "POSITION") { @@ -1239,6 +1249,11 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& int v2_index = (indices[n + 1] * 3); int v3_index = (indices[n + 2] * 3); + if (v1_index + 2 >= vertices.size() || v2_index + 2 >= vertices.size() || v3_index + 2 >= vertices.size()) { + qWarning(modelformat) << "Indices out of range for model " << _url; + break; + } + glm::vec3 v1 = glm::vec3(vertices[v1_index], vertices[v1_index + 1], vertices[v1_index + 2]); glm::vec3 v2 = glm::vec3(vertices[v2_index], vertices[v2_index + 1], vertices[v2_index + 2]); glm::vec3 v3 = glm::vec3(vertices[v3_index], vertices[v3_index + 1], vertices[v3_index + 2]); @@ -1333,7 +1348,7 @@ bool GLTFSerializer::buildGeometry(HFMModel& hfmModel, const hifi::VariantHash& } if (validatedIndices.size() == 0) { - qWarning(modelformat) << "Indices out of range for model " << _url; + qWarning(modelformat) << "No valid indices for model " << _url; continue; } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp index f4e81448cc..c9a5856a8d 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTextureTransfer.cpp @@ -15,7 +15,7 @@ #define OVERSUBSCRIBED_PRESSURE_VALUE 0.95f #define UNDERSUBSCRIBED_PRESSURE_VALUE 0.85f -#define DEFAULT_ALLOWED_TEXTURE_MEMORY_MB ((size_t)1024) +#define DEFAULT_ALLOWED_TEXTURE_MEMORY_MB ((size_t)2048) #define MAX_RESOURCE_TEXTURES_PER_FRAME 2 #define NO_BUFFER_WORK_SLEEP_TIME_MS 2 #define THREADED_TEXTURE_BUFFERING 1 diff --git a/libraries/hfm/src/hfm/HFM.h b/libraries/hfm/src/hfm/HFM.h index 7111ad2e65..d37d509d38 100644 --- a/libraries/hfm/src/hfm/HFM.h +++ b/libraries/hfm/src/hfm/HFM.h @@ -51,7 +51,7 @@ using ColorType = glm::vec3; #define HFM_COLOR_ELEMENT gpu::Element::VEC3F_XYZ #endif -const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048; +const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 8192 * 8192; using ShapeVertices = std::vector; diff --git a/libraries/image/src/image/TextureProcessing.cpp b/libraries/image/src/image/TextureProcessing.cpp index c144ed530a..53991ae431 100644 --- a/libraries/image/src/image/TextureProcessing.cpp +++ b/libraries/image/src/image/TextureProcessing.cpp @@ -41,7 +41,7 @@ using namespace gpu; static const glm::uvec2 SPARSE_PAGE_SIZE(128); static const glm::uvec2 MAX_TEXTURE_SIZE_GLES(2048); -static const glm::uvec2 MAX_TEXTURE_SIZE_GL(4096); +static const glm::uvec2 MAX_TEXTURE_SIZE_GL(8192); bool DEV_DECIMATE_TEXTURES = false; std::atomic DECIMATED_TEXTURE_COUNT{ 0 }; std::atomic RECTIFIED_TEXTURE_COUNT{ 0 }; diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 83c0fd28dd..5589defd80 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -508,7 +508,9 @@ bool AccountManager::checkAndSignalForAccessToken() { if (!hasToken) { // emit a signal so somebody can call back to us and request an access token given a username and password - emit authRequired(); + + // Dialog can be hidden immediately after showing if we've just teleported to the domain, unless the signal is delayed. + QTimer::singleShot(500, this, [this] { emit this->authRequired(); }); } return hasToken; diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 26fbe502a0..edc7b652b4 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -58,7 +58,7 @@ const auto METAVERSE_SESSION_ID_HEADER = QString("HFM-SessionID").toLocal8Bit(); using UserAgentGetter = std::function; -const auto DEFAULT_USER_AGENT_GETTER = []() -> QString { return HIGH_FIDELITY_USER_AGENT; }; +const auto DEFAULT_USER_AGENT_GETTER = []() -> QString { return NetworkingConstants::VIRCADIA_USER_AGENT; }; class AccountManager : public QObject, public Dependency { Q_OBJECT diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 8bdb777f96..148c4f8580 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -249,8 +249,9 @@ public slots: * Takes you to a specified metaverse address. * @function location.handleLookupString * @param {string} address - The address to go to: a "hifi://" address, an IP address (e.g., - * "127.0.0.1" or "localhost"), a domain name, a named path on a domain (starts with - * "/"), a position or position and orientation, or a user (starts with "@"). + * "127.0.0.1" or "localhost"), a file:/// address, a domain name, a named path + * on a domain (starts with "/"), a position or position and orientation, or a user (starts with + * "@"). * @param {boolean} [fromSuggestions=false] - Set to true if the address is obtained from the "Goto" dialog. * Helps ensure that user's location history is correctly maintained. */ diff --git a/libraries/networking/src/DomainAccountManager.cpp b/libraries/networking/src/DomainAccountManager.cpp new file mode 100644 index 0000000000..928b581a5b --- /dev/null +++ b/libraries/networking/src/DomainAccountManager.cpp @@ -0,0 +1,203 @@ +// +// DomainAccountManager.cpp +// libraries/networking/src +// +// Created by David Rowe on 23 Jul 2020. +// Copyright 2020 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "DomainAccountManager.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "NetworkingConstants.h" +#include "NetworkAccessManager.h" +#include "NetworkLogging.h" +#include "NodeList.h" + +// FIXME: Generalize to other OAuth2 sources for domain login. + +const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false; + +// ####### TODO: Enable and use these? +// ####### TODO: Add storing domain URL and check against it when retrieving values? +// ####### TODO: Add storing _authURL and check against it when retrieving values? +/* +Setting::Handle domainAccessToken {"private/domainAccessToken", "" }; +Setting::Handle domainAccessRefreshToken {"private/domainAccessToken", "" }; +Setting::Handle domainAccessTokenExpiresIn {"private/domainAccessTokenExpiresIn", -1 }; +Setting::Handle domainAccessTokenType {"private/domainAccessTokenType", "" }; +*/ + +DomainAccountManager::DomainAccountManager() : + _authURL(), + _username(), + _access_token(), + _refresh_token(), + _domain_name() +{ + connect(this, &DomainAccountManager::loginComplete, this, &DomainAccountManager::sendInterfaceAccessTokenToServer); +} + +void DomainAccountManager::setAuthURL(const QUrl& authURL) { + if (_authURL != authURL) { + _authURL = authURL; + + qCDebug(networking) << "AccountManager URL for authenticated requests has been changed to" << qPrintable(_authURL.toString()); + + _access_token = ""; + _refresh_token = ""; + + // ####### TODO: Restore and refresh OAuth2 tokens if have them for this domain. + + // ####### TODO: Handle "keep me logged in". + } +} + +bool DomainAccountManager::isLoggedIn() { + return !_authURL.isEmpty() && hasValidAccessToken(); +} + +void DomainAccountManager::requestAccessToken(const QString& username, const QString& password) { + + _username = username; + _access_token = ""; + _refresh_token = ""; + + QNetworkRequest request; + + request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); + + // miniOrange WordPress API Authentication plugin: + // - Requires "client_id" parameter. + // - Ignores "state" parameter. + QByteArray formData; + formData.append("grant_type=password&"); + formData.append("username=" + QUrl::toPercentEncoding(username) + "&"); + formData.append("password=" + QUrl::toPercentEncoding(password) + "&"); + formData.append("client_id=" + _clientID); + + request.setUrl(_authURL); + + request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); + + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + QNetworkReply* requestReply = networkAccessManager.post(request, formData); + connect(requestReply, &QNetworkReply::finished, this, &DomainAccountManager::requestAccessTokenFinished); +} + +void DomainAccountManager::requestAccessTokenFinished() { + + QNetworkReply* requestReply = reinterpret_cast(sender()); + + QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll()); + const QJsonObject& rootObject = jsonResponse.object(); + + auto httpStatus = requestReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + if (200 <= httpStatus && httpStatus < 300) { + + // miniOrange plugin provides no scope. + if (rootObject.contains("access_token")) { + // Success. + auto nodeList = DependencyManager::get(); + _domain_name = nodeList->getDomainHandler().getHostname(); + QUrl rootURL = requestReply->url(); + rootURL.setPath(""); + setTokensFromJSON(rootObject, rootURL); + emit loginComplete(); + } else { + // Failure. + qCDebug(networking) << "Received a response for password grant that is missing one or more expected values."; + emit loginFailed(); + } + + } else { + // Failure. + qCDebug(networking) << "Error in response for password grant -" << httpStatus << requestReply->error() + << "-" << rootObject["error"].toString() << rootObject["error_description"].toString(); + emit loginFailed(); + } +} + +void DomainAccountManager::sendInterfaceAccessTokenToServer() { + emit newTokens(); +} + +bool DomainAccountManager::accessTokenIsExpired() { + // ####### TODO: accessTokenIsExpired() + return true; + /* + return domainAccessTokenExpiresIn.get() != -1 && domainAccessTokenExpiresIn.get() <= QDateTime::currentMSecsSinceEpoch(); + */ +} + + +bool DomainAccountManager::hasValidAccessToken() { + // ###### TODO: wire this up to actually retrieve a token (based on session or storage) and confirm that it is in fact valid and relevant to the current domain. + // QString currentDomainAccessToken = domainAccessToken.get(); + QString currentDomainAccessToken = _access_token; + + // if (currentDomainAccessToken.isEmpty() || accessTokenIsExpired()) { + if (currentDomainAccessToken.isEmpty()) { + if (VERBOSE_HTTP_REQUEST_DEBUGGING) { + qCDebug(networking) << "An access token is required for requests to" + << qPrintable(_authURL.toString()); + } + + return false; + } + + // ####### TODO + + // if (!_isWaitingForTokenRefresh && needsToRefreshToken()) { + // refreshAccessToken(); + // } + + return true; +} + +void DomainAccountManager::setTokensFromJSON(const QJsonObject& jsonObject, const QUrl& url) { + _access_token = jsonObject["access_token"].toString(); + _refresh_token = jsonObject["refresh_token"].toString(); + + // ####### TODO: Enable and use these? + // ####### TODO: Protect these per AccountManager? + // ######: TODO: clientID needed? + // qCDebug(networking) << "Storing a domain account with access-token for" << qPrintable(url.toString()); + // domainAccessToken.set(jsonObject["access_token"].toString()); + // domainAccessRefreshToken.set(jsonObject["refresh_token"].toString()); + // domainAccessTokenExpiresIn.set(QDateTime::currentMSecsSinceEpoch() + (jsonObject["expires_in"].toDouble() * 1000)); + // domainAccessTokenType.set(jsonObject["token_type"].toString()); +} + +bool DomainAccountManager::checkAndSignalForAccessToken() { + bool hasToken = hasValidAccessToken(); + + // ####### TODO: Handle hasToken == true. + // It causes the login dialog not to display (OK) but somewhere the domain server needs to be sent it (and if domain server + // gets error when trying to use it then user should be prompted to login). + hasToken = false; + + if (!hasToken) { + // Emit a signal so somebody can call back to us and request an access token given a user name and password. + + // Dialog can be hidden immediately after showing if we've just teleported to the domain, unless the signal is delayed. + auto domain = _authURL.host(); + QTimer::singleShot(500, this, [this, domain] { + emit this->authRequired(domain); + }); + } + + return hasToken; +} diff --git a/libraries/networking/src/DomainAccountManager.h b/libraries/networking/src/DomainAccountManager.h new file mode 100644 index 0000000000..31226d6990 --- /dev/null +++ b/libraries/networking/src/DomainAccountManager.h @@ -0,0 +1,66 @@ +// +// DomainAccountManager.h +// libraries/networking/src +// +// Created by David Rowe on 23 Jul 2020. +// Copyright 2020 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_DomainAccountManager_h +#define hifi_DomainAccountManager_h + +#include +#include + +#include + + +class DomainAccountManager : public QObject, public Dependency { + Q_OBJECT +public: + DomainAccountManager(); + + void setAuthURL(const QUrl& authURL); + void setClientID(const QString& clientID) { _clientID = clientID; } + + QString getUsername() { return _username; } + QString getAccessToken() { return _access_token; } + QString getRefreshToken() { return _refresh_token; } + QString getAuthedDomain() { return _domain_name; } + + bool isLoggedIn(); + + Q_INVOKABLE bool checkAndSignalForAccessToken(); + +public slots: + void requestAccessToken(const QString& username, const QString& password); + + void requestAccessTokenFinished(); + +signals: + void authRequired(const QString& domain); + void loginComplete(); + void loginFailed(); + void logoutComplete(); + void newTokens(); + +private slots: + +private: + bool hasValidAccessToken(); + bool accessTokenIsExpired(); + void setTokensFromJSON(const QJsonObject&, const QUrl& url); + void sendInterfaceAccessTokenToServer(); + + QUrl _authURL; + QString _clientID; + QString _username; // ####### TODO: Store elsewhere? + QString _access_token; // ####... "" + QString _refresh_token; // ####... "" + QString _domain_name; // ####... "" +}; + +#endif // hifi_DomainAccountManager_h diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index d34b5cf090..c1a24748f4 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -4,6 +4,7 @@ // // Created by Stephen Birarda on 2/18/2014. // Copyright 2014 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -24,6 +25,7 @@ #include "AddressManager.h" #include "Assignment.h" +#include "DomainAccountManager.h" #include "HifiSockAddr.h" #include "NodeList.h" #include "udt/Packet.h" @@ -144,7 +146,8 @@ void DomainHandler::hardReset(QString reason) { bool DomainHandler::isHardRefusal(int reasonCode) { return (reasonCode == (int)ConnectionRefusedReason::ProtocolMismatch || reasonCode == (int)ConnectionRefusedReason::TooManyUsers || - reasonCode == (int)ConnectionRefusedReason::NotAuthorized || + reasonCode == (int)ConnectionRefusedReason::NotAuthorizedMetaverse || + reasonCode == (int)ConnectionRefusedReason::NotAuthorizedDomain || reasonCode == (int)ConnectionRefusedReason::TimedOut); } @@ -219,6 +222,8 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) { QString previousHost = _domainURL.host(); _domainURL = domainURL; + _hasCheckedForDomainAccessToken = false; + if (previousHost != domainURL.host()) { qCDebug(networking) << "Updated domain hostname to" << domainURL.host(); @@ -489,16 +494,33 @@ void DomainHandler::processICEResponsePacket(QSharedPointer mes } } -bool DomainHandler::reasonSuggestsLogin(ConnectionRefusedReason reasonCode) { +bool DomainHandler::reasonSuggestsMetaverseLogin(ConnectionRefusedReason reasonCode) { switch (reasonCode) { - case ConnectionRefusedReason::LoginError: - case ConnectionRefusedReason::NotAuthorized: + case ConnectionRefusedReason::LoginErrorMetaverse: + case ConnectionRefusedReason::NotAuthorizedMetaverse: return true; default: case ConnectionRefusedReason::Unknown: case ConnectionRefusedReason::ProtocolMismatch: case ConnectionRefusedReason::TooManyUsers: + case ConnectionRefusedReason::NotAuthorizedDomain: + return false; + } + return false; +} + +bool DomainHandler::reasonSuggestsDomainLogin(ConnectionRefusedReason reasonCode) { + switch (reasonCode) { + case ConnectionRefusedReason::LoginErrorDomain: + case ConnectionRefusedReason::NotAuthorizedDomain: + return true; + + default: + case ConnectionRefusedReason::Unknown: + case ConnectionRefusedReason::ProtocolMismatch: + case ConnectionRefusedReason::TooManyUsers: + case ConnectionRefusedReason::NotAuthorizedMetaverse: return false; } return false; @@ -528,7 +550,9 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer(); - // Some connection refusal reasons imply that a login is required. If so, suggest a new login - if (reasonSuggestsLogin(reasonCode)) { - qCWarning(networking) << "Make sure you are logged in."; + // Some connection refusal reasons imply that a login is required. If so, suggest a new login. + if (reasonSuggestsMetaverseLogin(reasonCode)) { + qCWarning(networking) << "Make sure you are logged in to the metaverse."; + + auto accountManager = DependencyManager::get(); if (!_hasCheckedForAccessToken) { accountManager->checkAndSignalForAccessToken(); @@ -559,6 +584,23 @@ void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointergenerateNewUserKeypair(); _connectionDenialsSinceKeypairRegen = 0; } + } else if (reasonSuggestsDomainLogin(reasonCode)) { + qCWarning(networking) << "Make sure you are logged in to the domain."; + + auto accountManager = DependencyManager::get(); + if (!extraInfo.isEmpty()) { + auto extraInfoComponents = extraInfo.split("|"); + accountManager->setAuthURL(extraInfoComponents.value(0)); + accountManager->setClientID(extraInfoComponents.value(1)); + } + + if (!_hasCheckedForDomainAccessToken) { + accountManager->checkAndSignalForAccessToken(); + _hasCheckedForDomainAccessToken = true; + } + + // ####### TODO: regenerate key-pair after several failed connection attempts, similar to metaverse login code? + } } diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 50ebc1edbc..f77ff2bb5b 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -4,6 +4,7 @@ // // Created by Stephen Birarda on 2/18/2014. // Copyright 2014 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -131,6 +132,7 @@ public: bool isConnected() const { return _isConnected; } void setIsConnected(bool isConnected); + bool isServerless() const { return _domainURL.scheme() != URL_SCHEME_HIFI; } bool getInterstitialModeEnabled() const; void setInterstitialModeEnabled(bool enableInterstitialMode); @@ -179,14 +181,14 @@ public: * The communications protocols of the domain and your Interface are not the same. * * - * LoginError + * LoginErrorMetaverse * 2 - * You could not be logged into the domain. + * You could not be logged into the domain per your metaverse login. * * - * NotAuthorized + * NotAuthorizedMetaverse * 3 - * You are not authorized to connect to the domain. + * You are not authorized to connect to the domain per your metaverse login. * * * TooManyUsers @@ -198,6 +200,16 @@ public: * 5 * Connecting to the domain timed out. * + * + * LoginErrorDomain + * 2 + * You could not be logged into the domain per your domain login. + * + * + * NotAuthorizedDomain + * 6 + * You are not authorized to connect to the domain per your domain login. + * * * * @typedef {number} Window.ConnectionRefusedReason @@ -205,10 +217,12 @@ public: enum class ConnectionRefusedReason : uint8_t { Unknown, ProtocolMismatch, - LoginError, - NotAuthorized, + LoginErrorMetaverse, + NotAuthorizedMetaverse, TooManyUsers, - TimedOut + TimedOut, + LoginErrorDomain, + NotAuthorizedDomain }; public slots: @@ -254,7 +268,8 @@ signals: void limitOfSilentDomainCheckInsReached(); private: - bool reasonSuggestsLogin(ConnectionRefusedReason reasonCode); + bool reasonSuggestsMetaverseLogin(ConnectionRefusedReason reasonCode); + bool reasonSuggestsDomainLogin(ConnectionRefusedReason reasonCode); void sendDisconnectPacket(); void hardReset(QString reason); @@ -285,6 +300,7 @@ private: QSet _domainConnectionRefusals; bool _hasCheckedForAccessToken { false }; + bool _hasCheckedForDomainAccessToken { false }; int _connectionDenialsSinceKeypairRegen { 0 }; int _checkInPacketsSinceLastReply { 0 }; diff --git a/libraries/networking/src/HTTPResourceRequest.cpp b/libraries/networking/src/HTTPResourceRequest.cpp index 50221a136a..b13b66f740 100644 --- a/libraries/networking/src/HTTPResourceRequest.cpp +++ b/libraries/networking/src/HTTPResourceRequest.cpp @@ -21,6 +21,7 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" +#include "NetworkingConstants.h" HTTPResourceRequest::~HTTPResourceRequest() { if (_reply) { @@ -54,7 +55,7 @@ void HTTPResourceRequest::doSend() { QNetworkRequest networkRequest(_url); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); if (_cacheEnabled) { networkRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h index 1d28205310..edc1c1a1ef 100644 --- a/libraries/networking/src/NetworkingConstants.h +++ b/libraries/networking/src/NetworkingConstants.h @@ -30,6 +30,14 @@ namespace NetworkingConstants { // Web Engine requests to this parent domain have an account authorization header added const QString AUTH_HOSTNAME_BASE = "highfidelity.com"; + const QStringList IS_AUTHABLE_HOSTNAME = { "highfidelity.com", "highfidelity.io" }; + + // Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers. + const QByteArray VIRCADIA_USER_AGENT = "Mozilla/5.0 (VircadiaInterface)"; + + const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (VircadiaInterface)"; + const QString METAVERSE_USER_AGENT = "Chrome/48.0 (VircadiaInterface)"; + const QString MOBILE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml"); const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml"); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 2c584b1c48..e02a8dd56e 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -4,6 +4,7 @@ // // Created by Stephen Birarda on 2/15/13. // Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -33,6 +34,7 @@ #include "AddressManager.h" #include "Assignment.h" #include "AudioHelpers.h" +#include "DomainAccountManager.h" #include "HifiSockAddr.h" #include "FingerprintUtils.h" @@ -103,6 +105,13 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) // clear our NodeList when logout is requested connect(accountManager.data(), &AccountManager::logoutComplete , this, [this]{ reset("Logged out"); }); + // Only used in Interface. + auto domainAccountManager = DependencyManager::get(); + if (domainAccountManager) { + _hasDomainAccountManager = true; + connect(domainAccountManager.data(), &DomainAccountManager::newTokens, this, &NodeList::sendDomainServerCheckIn); + } + // anytime we get a new node we will want to attempt to punch to it connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch); connect(this, &LimitedNodeList::nodeSocketUpdated, this, &NodeList::startNodeHolePunch); @@ -379,6 +388,7 @@ void NodeList::sendDomainServerCheckIn() { if (domainPacketType == PacketType::DomainConnectRequest) { #if (PR_BUILD || DEV_BUILD) + // ####### if (_shouldSendNewerVersion) { domainPacket->setVersion(versionForPacketType(domainPacketType) + 1); } @@ -466,6 +476,7 @@ void NodeList::sendDomainServerCheckIn() { packetStream << _ownerType.load() << publicSockAddr << localSockAddr << _nodeTypesOfInterest.toList(); packetStream << DependencyManager::get()->getPlaceName(); + // ####### TODO: Also send if need to send new domainLogin data? if (!domainIsConnected) { DataServerAccountInfo& accountInfo = accountManager->getAccountInfo(); packetStream << accountInfo.getUsername(); @@ -474,6 +485,23 @@ void NodeList::sendDomainServerCheckIn() { if (requiresUsernameSignature && accountManager->getAccountInfo().hasPrivateKey()) { const QByteArray& usernameSignature = accountManager->getAccountInfo().getUsernameSignature(connectionToken); packetStream << usernameSignature; + } else { + // ####### TODO: Only append if are going to send domain username? + packetStream << QString(""); // Placeholder in case have domain username. + } + } else { + // ####### TODO: Only append if are going to send domainUsername? + packetStream << QString("") << QString(""); // Placeholders in case have domain username. + } + + // Send domain domain login data from Interface to domain server. + if (_hasDomainAccountManager) { + auto domainAccountManager = DependencyManager::get(); + if (!domainAccountManager->getUsername().isEmpty()) { + packetStream << domainAccountManager->getUsername(); + if (!domainAccountManager->getAccessToken().isEmpty()) { + packetStream << (domainAccountManager->getAccessToken() + ":" + domainAccountManager->getRefreshToken()); + } } } diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index c377ea89cb..4954c53c84 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -196,6 +196,8 @@ private: #if (PR_BUILD || DEV_BUILD) bool _shouldSendNewerVersion { false }; #endif + + bool _hasDomainAccountManager { false }; }; #endif // hifi_NodeList_h diff --git a/libraries/networking/src/NodePermissions.h b/libraries/networking/src/NodePermissions.h index 583c1b29ac..82c008feef 100644 --- a/libraries/networking/src/NodePermissions.h +++ b/libraries/networking/src/NodePermissions.h @@ -4,6 +4,7 @@ // // Created by Seth Alves on 2016-6-1. // Copyright 2016 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -51,6 +52,9 @@ public: void setVerifiedUserName(QString userName) { _verifiedUserName = userName.toLower(); } const QString& getVerifiedUserName() const { return _verifiedUserName; } + void setVerifiedDomainUserName(QString userName) { _verifiedDomainUserName = userName.toLower(); } + const QString& getVerifiedDomainUserName() const { return _verifiedDomainUserName; } + void setGroupID(QUuid groupID) { _groupID = groupID; if (!groupID.isNull()) { _groupIDSet = true; }} QUuid getGroupID() const { return _groupID; } bool isGroup() const { return _groupIDSet; } @@ -99,6 +103,7 @@ protected: QString _id; QUuid _rankID { QUuid() }; // 0 unless this is for a group QString _verifiedUserName; + QString _verifiedDomainUserName; bool _groupIDSet { false }; QUuid _groupID; diff --git a/libraries/networking/src/OAuthNetworkAccessManager.cpp b/libraries/networking/src/OAuthNetworkAccessManager.cpp index b1e04da4b6..a036588646 100644 --- a/libraries/networking/src/OAuthNetworkAccessManager.cpp +++ b/libraries/networking/src/OAuthNetworkAccessManager.cpp @@ -39,7 +39,7 @@ QNetworkReply* OAuthNetworkAccessManager::createRequest(QNetworkAccessManager::O && req.url().host() == MetaverseAPI::getCurrentMetaverseServerURL().host()) { QNetworkRequest authenticatedRequest(req); authenticatedRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + authenticatedRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); authenticatedRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, accountManager->getAccountInfo().getAccessToken().authorizationHeaderValue()); diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index f4f5525ddc..0b9d5a2d60 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -25,6 +25,7 @@ #include "HTTPResourceRequest.h" #include "NetworkAccessManager.h" #include "NetworkLogging.h" +#include "NetworkingConstants.h" ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) { _thread.setObjectName("Resource Manager Thread"); @@ -157,7 +158,7 @@ bool ResourceManager::resourceExists(const QUrl& url) { QNetworkRequest request{ url }; request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); auto reply = networkAccessManager.head(request); diff --git a/libraries/networking/src/SandboxUtils.cpp b/libraries/networking/src/SandboxUtils.cpp index 4a348b0662..e3ef2a787d 100644 --- a/libraries/networking/src/SandboxUtils.cpp +++ b/libraries/networking/src/SandboxUtils.cpp @@ -22,6 +22,7 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" +#include "NetworkingConstants.h" namespace SandboxUtils { @@ -29,7 +30,7 @@ QNetworkReply* getStatus() { auto& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest sandboxStatus(SANDBOX_STATUS_URL); sandboxStatus.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - sandboxStatus.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + sandboxStatus.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); return networkAccessManager.get(sandboxStatus); } diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index aac0de27a1..897ac142bf 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -734,7 +734,8 @@ QString getMarketplaceID(const QString& urlString) { bool Octree::readFromURL( const QString& urlString, const bool isObservable, - const qint64 callerId + const qint64 callerId, + const bool isImport ) { QString trimmedUrl = urlString.trimmed(); QString marketplaceID = getMarketplaceID(trimmedUrl); @@ -766,7 +767,7 @@ bool Octree::readFromURL( } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID); + return readFromStream(data.size(), inputStream, marketplaceID, isImport); } bool Octree::readFromByteArray( @@ -791,7 +792,8 @@ bool Octree::readFromByteArray( bool Octree::readFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID + const QString& marketplaceID, + const bool isImport ) { // decide if this is binary SVO or JSON-formatted SVO QIODevice *device = inputStream.device(); @@ -804,7 +806,7 @@ bool Octree::readFromStream( return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; - return readJSONFromStream(streamLength, inputStream, marketplaceID); + return readJSONFromStream(streamLength, inputStream, marketplaceID, isImport); } } @@ -834,7 +836,8 @@ const int READ_JSON_BUFFER_SIZE = 2048; bool Octree::readJSONFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID /*=""*/ + const QString& marketplaceID, /*=""*/ + const bool isImport ) { // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // we get an eof. Leave streamLength parameter for consistency. @@ -866,7 +869,7 @@ bool Octree::readJSONFromStream( addMarketplaceIDToDocumentEntities(asMap, marketplaceID); } - bool success = readFromMap(asMap); + bool success = readFromMap(asMap, isImport); delete[] rawData; return success; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 45dae3049d..a7885801de 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -216,13 +216,12 @@ public: // Octree importers bool readFromFile(const char* filename); - bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1); // will support file urls as well... + bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const bool isImport = false); // will support file urls as well... bool readFromByteArray(const QString& url, const QByteArray& byteArray); - bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); - bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream); - bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); + bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false); + bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const bool isImport = false); bool readJSONFromGzippedFile(QString qFileName); - virtual bool readFromMap(QVariantMap& entityDescription) = 0; + virtual bool readFromMap(QVariantMap& entityDescription, const bool isImport = false) = 0; uint64_t getOctreeElementsCount(); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index a796ea28a0..e222692aea 100755 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -543,12 +543,8 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& minCorner, const _minStepHeight = DEFAULT_MIN_STEP_HEIGHT_FACTOR * (_halfHeight + _radius); _maxStepHeight = DEFAULT_MAX_STEP_HEIGHT_FACTOR * (_halfHeight + _radius); - if (_physicsEngine) { - // must REMOVE from world prior to shape update - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_REMOVE_DETAILED_FROM_SIMULATION; - } - _pendingFlags |= PENDING_FLAG_UPDATE_SHAPE; - _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_ADD_DETAILED_TO_SIMULATION; + _pendingFlags |= PENDING_FLAG_UPDATE_SHAPE | PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_REMOVE_DETAILED_FROM_SIMULATION | + PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_ADD_DETAILED_TO_SIMULATION; } // it's ok to change offset immediately -- there are no thread safety issues here diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 3776c4e199..6150097f14 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -226,6 +226,7 @@ void Model::updateRenderItems() { modelTransform.setScale(glm::vec3(1.0f)); PrimitiveMode primitiveMode = self->getPrimitiveMode(); + auto renderWithZones = self->getRenderWithZones(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool cauterized = self->isCauterized(); @@ -241,7 +242,8 @@ void Model::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, - invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { + invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, + cauterized, renderWithZones](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); @@ -268,6 +270,7 @@ void Model::updateRenderItems() { data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.setCauterized(cauterized); + data.setRenderWithZones(renderWithZones); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); @@ -282,11 +285,6 @@ void Model::setRenderItemsNeedUpdate() { emit requestRenderUpdate(); } -void Model::setPrimitiveMode(PrimitiveMode primitiveMode) { - _primitiveMode = primitiveMode; - setRenderItemsNeedUpdate(); -} - void Model::reset() { if (isLoaded()) { const HFMModel& hfmModel = getHFMModel(); @@ -960,6 +958,13 @@ void Model::setCauterized(bool cauterized, const render::ScenePointer& scene) { } } +void Model::setPrimitiveMode(PrimitiveMode primitiveMode) { + if (_primitiveMode != primitiveMode) { + _primitiveMode = primitiveMode; + setRenderItemsNeedUpdate(); + } +} + void Model::setCullWithParent(bool cullWithParent) { if (_cullWithParent != cullWithParent) { _cullWithParent = cullWithParent; @@ -977,13 +982,10 @@ void Model::setCullWithParent(bool cullWithParent) { } void Model::setRenderWithZones(const QVector& renderWithZones) { - render::Transaction transaction; - for (auto item : _modelMeshRenderItemIDs) { - transaction.updateItem(item, [renderWithZones](ModelMeshPartPayload& data) { - data.setRenderWithZones(renderWithZones); - }); + if (_renderWithZones != renderWithZones) { + _renderWithZones = renderWithZones; + setRenderItemsNeedUpdate(); } - AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); } const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index bdb4a35071..412a1b7638 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -121,6 +121,7 @@ public: void setCullWithParent(bool value); void setRenderWithZones(const QVector& renderWithZones); + const QVector& getRenderWithZones() const { return _renderWithZones; } // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; @@ -499,6 +500,7 @@ protected: render::ItemKey _renderItemKeyGlobalFlags; bool _cauterized { false }; bool _cullWithParent { false }; + QVector _renderWithZones; bool shouldInvalidatePayloadShapeKey(int meshIndex); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 5cb5709252..024be6598d 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -15,6 +15,7 @@ #include "../StencilMaskPass.h" #include "NetworkAccessManager.h" +#include "NetworkingConstants.h" static std::mutex fontMutex; @@ -97,7 +98,7 @@ Font::Pointer Font::load(const QString& family) { QNetworkRequest networkRequest; networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); networkRequest.setUrl(family); auto networkReply = networkAccessManager.get(networkRequest); diff --git a/libraries/script-engine/src/ScriptsModel.cpp b/libraries/script-engine/src/ScriptsModel.cpp index 429c7f5518..40482c12ee 100644 --- a/libraries/script-engine/src/ScriptsModel.cpp +++ b/libraries/script-engine/src/ScriptsModel.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include "ScriptEngine.h" @@ -191,7 +192,7 @@ void ScriptsModel::requestDefaultFiles(QString marker) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest request(url); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); - request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); QNetworkReply* reply = networkAccessManager.get(request); connect(reply, SIGNAL(finished()), SLOT(downloadFinished())); } diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index b0ceca5758..1a4ec52f73 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -62,7 +62,7 @@ void XMLHttpRequestClass::abort() { } void XMLHttpRequestClass::setRequestHeader(const QString& name, const QString& value) { - _request.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + _request.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::VIRCADIA_USER_AGENT); _request.setRawHeader(QByteArray(name.toLatin1()), QByteArray(value.toLatin1())); } diff --git a/libraries/shared/src/NumericalConstants.h b/libraries/shared/src/NumericalConstants.h index 8377c48960..b7fecfa1e4 100644 --- a/libraries/shared/src/NumericalConstants.h +++ b/libraries/shared/src/NumericalConstants.h @@ -28,8 +28,8 @@ const float ARCSECONDS_PER_ARCMINUTE = 60.0f; const float ARCSECONDS_PER_DEGREE = ARCMINUTES_PER_DEGREE * ARCSECONDS_PER_ARCMINUTE; const float EPSILON = 0.000001f; //smallish positive number - used as margin of error for some computations -const float SQUARE_ROOT_OF_2 = (float)sqrt(2.0f); -const float SQUARE_ROOT_OF_3 = (float)sqrt(3.0f); +const float SQUARE_ROOT_OF_2 = 1.414214f; +const float SQUARE_ROOT_OF_3 = 1.732051f; const float METERS_PER_DECIMETER = 0.1f; const float METERS_PER_CENTIMETER = 0.01f; const float METERS_PER_MILLIMETER = 0.001f; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 709eeca9b2..c40cae5f76 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -81,9 +81,6 @@ const int BYTES_PER_FLAGS = 1; typedef unsigned char colorPart; typedef unsigned char nodeColor[BYTES_PER_COLOR + BYTES_PER_FLAGS]; -// Use a custom User-Agent to avoid ModSecurity filtering, e.g. by hosting providers. -const QByteArray HIGH_FIDELITY_USER_AGENT = "Mozilla/5.0 (HighFidelityInterface)"; - // Equivalent to time_t but in usecs instead of secs quint64 usecTimestampNow(bool wantDebug = false); void usecTimestampNowForceClockSkew(qint64 clockSkew); diff --git a/libraries/ui/src/ui/types/FileTypeProfile.cpp b/libraries/ui/src/ui/types/FileTypeProfile.cpp index 3b9ed74200..9fca1be436 100644 --- a/libraries/ui/src/ui/types/FileTypeProfile.cpp +++ b/libraries/ui/src/ui/types/FileTypeProfile.cpp @@ -16,6 +16,7 @@ #include #include "RequestFilters.h" +#include "NetworkingConstants.h" #if !defined(Q_OS_ANDROID) static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine"; @@ -26,8 +27,7 @@ static std::mutex FileTypeProfile_mutex; FileTypeProfile::FileTypeProfile(QQmlContext* parent) : ContextAwareProfile(parent) { - static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)"; - setHttpUserAgent(WEB_ENGINE_USER_AGENT); + setHttpUserAgent(NetworkingConstants::WEB_ENGINE_USER_AGENT); setStorageName(QML_WEB_ENGINE_STORAGE_NAME); setOffTheRecord(false); diff --git a/libraries/ui/src/ui/types/RequestFilters.cpp b/libraries/ui/src/ui/types/RequestFilters.cpp index 9287559289..0eea5230ca 100644 --- a/libraries/ui/src/ui/types/RequestFilters.cpp +++ b/libraries/ui/src/ui/types/RequestFilters.cpp @@ -27,10 +27,10 @@ namespace { bool isAuthableHighFidelityURL(const QUrl& url) { auto metaverseServerURL = MetaverseAPI::getCurrentMetaverseServerURL(); - static const QStringList HF_HOSTS = { - "highfidelity.com", "highfidelity.io", - metaverseServerURL.toString(), + static QStringList HF_HOSTS = { + metaverseServerURL.toString() }; + HF_HOSTS << NetworkingConstants::IS_AUTHABLE_HOSTNAME; const auto& scheme = url.scheme(); const auto& host = url.host(); @@ -83,9 +83,9 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info, } } static const QString USER_AGENT = "User-Agent"; - const QString tokenStringMobile{ "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36" }; - const QString tokenStringMetaverse{ "Chrome/48.0 (HighFidelityInterface)" }; - const QString tokenStringLimitedCommerce{ "Chrome/48.0 (HighFidelityInterface limitedCommerce)" }; + const QString tokenStringMobile{ NetworkingConstants::MOBILE_USER_AGENT }; + const QString tokenStringMetaverse{ NetworkingConstants::METAVERSE_USER_AGENT }; + const QString tokenStringLimitedCommerce{ "Chrome/48.0 (VircadiaInterface limitedCommerce)" }; const QString tokenString = !isAuthable ? tokenStringMobile : (accountManager->getLimitedCommerce() ? tokenStringLimitedCommerce : tokenStringMetaverse); info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit()); diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index e80b2215bf..9690ee3fb5 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -1,12 +1,13 @@ # # Created by Bradley Austin Davis on 2015/11/18 # Copyright 2015 High Fidelity, Inc. +# Copyright 2020 Vircadia contributors. # # Distributed under the Apache License, Version 2.0. # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -if (WIN32 AND (NOT USE_GLES)) +if ((WIN32 OR UNIX AND NOT APPLE) AND NOT USE_GLES) set(TARGET_NAME openvr) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui @@ -15,7 +16,9 @@ if (WIN32 AND (NOT USE_GLES)) include_hifi_library_headers(octree) target_openvr() - target_sranipal() - target_aristo() - target_link_libraries(${TARGET_NAME} Winmm.lib) + if (WIN32) + target_sranipal() + target_aristo() + target_link_libraries(${TARGET_NAME} Winmm.lib) + endif() endif() diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 7691d2ab70..c5eb740325 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -1,6 +1,7 @@ // // Created by Bradley Austin Davis on 2015/05/12 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -739,6 +740,8 @@ int OpenVrDisplayPlugin::getRequiredThreadCount() const { QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const { QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_RecordingDeviceOverride_String); + // FIXME: Address Linux. +#ifdef Q_OS_WIN if (!device.isEmpty()) { static const WCHAR INIT = 0; size_t size = device.size() + 1; @@ -748,11 +751,14 @@ QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const { // FIXME: This may not be necessary if vr::k_pch_audio_RecordingDeviceOverride_StringName is used above. device = AudioClient::getWinDeviceName(deviceW.data()); } +#endif return device; } QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const { QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_PlaybackDeviceOverride_String); + // FIXME: Address Linux. +#ifdef Q_OS_WIN if (!device.isEmpty()) { static const WCHAR INIT = 0; size_t size = device.size() + 1; @@ -762,6 +768,7 @@ QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const { // FIXME: This may not be necessary if vr::k_pch_audio_PlaybackDeviceOverride_StringName is used above. device = AudioClient::getWinDeviceName(deviceW.data()); } +#endif return device; } diff --git a/plugins/openvr/src/OpenVrHelpers.cpp b/plugins/openvr/src/OpenVrHelpers.cpp index e55e7feaf4..ce7625eedb 100644 --- a/plugins/openvr/src/OpenVrHelpers.cpp +++ b/plugins/openvr/src/OpenVrHelpers.cpp @@ -1,6 +1,7 @@ // // Created by Bradley Austin Davis on 2015/11/01 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -18,8 +19,6 @@ #include #include -#include -#include #include #include #include @@ -51,7 +50,7 @@ static const uint32_t RELEASE_OPENVR_HMD_DELAY_MS = 5000; bool isOculusPresent() { bool result = false; -#if defined(Q_OS_WIN32) +#ifdef Q_OS_WIN HANDLE oculusServiceEvent = ::OpenEventW(SYNCHRONIZE, FALSE, L"OculusHMDConnected"); // The existence of the service indicates a running Oculus runtime if (oculusServiceEvent) { @@ -208,8 +207,10 @@ void finishOpenVrKeyboardInput() { updateFromOpenVrKeyboardInput(); // Simulate an enter press on the top level window to trigger the action if (0 == (_currentHints & Qt::ImhMultiLine)) { - qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n"))); - qApp->sendEvent(offscreenUi->getWindow(), &QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers())); + auto keyPress = QKeyEvent(QEvent::KeyPress, Qt::Key_Return, Qt::KeyboardModifiers(), QString("\n")); + auto keyRelease = QKeyEvent(QEvent::KeyRelease, Qt::Key_Return, Qt::KeyboardModifiers()); + qApp->sendEvent(offscreenUi->getWindow(), &keyPress); + qApp->sendEvent(offscreenUi->getWindow(), &keyRelease); } } @@ -293,11 +294,20 @@ void handleOpenVrEvents() { ulong promitySensorFlag = (1UL << ((int)vr::k_EButton_ProximitySensor)); _headInHeadset = (controllerState.ulButtonPressed & promitySensorFlag) == promitySensorFlag; } - } #if DEV_BUILD - qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + //qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + // FIXME: Reinstate the line above and remove the following lines once the problem with excessive occurrences of + // VREvent_ActionBindingReloaded events is fixed in SteamVR for Linux. + // https://github.com/ValveSoftware/SteamVR-for-Linux/issues/307 + #ifdef Q_OS_LINUX + if (event.eventType != vr::VREvent_ActionBindingReloaded) { + qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + }; + #else + qDebug() << "OpenVR: Event " << activeHmd->GetEventTypeNameFromEnum((vr::EVREventType)event.eventType) << "(" << event.eventType << ")"; + #endif #endif } @@ -407,9 +417,32 @@ void showMinSpecWarning() { qFatal("Unable to create overlay"); } - // Needed here for PathUtils +#ifdef Q_OS_LINUX + QFile cmdlineFile("/proc/self/cmdline"); + if (!cmdlineFile.open(QIODevice::ReadOnly)) { + qFatal("Unable to open /proc/self/cmdline"); + } + + auto contents = cmdlineFile.readAll(); + auto arguments = contents.split('\0'); + arguments.pop_back(); // Last element is empty. + cmdlineFile.close(); + + int __argc = arguments.count(); + char** __argv = new char* [__argc]; + for (int i = 0; i < __argc; i++) { + __argv[i] = arguments[i].data(); + } +#endif + QCoreApplication miniApp(__argc, __argv); +#ifdef Q_OS_LINUX + QObject::connect(&miniApp, &QCoreApplication::destroyed, [=] { + delete[] __argv; + }); +#endif + vrSystem->ResetSeatedZeroPose(); QString imagePath = PathUtils::resourcesPath() + "/images/steam-min-spec-failed.png"; vrOverlay->SetOverlayFromFile(minSpecFailedOverlay, imagePath.toLocal8Bit().toStdString().c_str()); @@ -487,7 +520,12 @@ bool checkMinSpecImpl() { } extern "C" { +#if defined(Q_OS_WIN32) __declspec(dllexport) int __stdcall CheckMinSpec() { +#else + __attribute__((visibility("default"))) int CheckMinSpec() { +#endif return checkMinSpecImpl() ? 1 : 0; } + } diff --git a/plugins/openvr/src/OpenVrHelpers.h b/plugins/openvr/src/OpenVrHelpers.h index b0960a03eb..23bd9f39de 100644 --- a/plugins/openvr/src/OpenVrHelpers.h +++ b/plugins/openvr/src/OpenVrHelpers.h @@ -1,6 +1,7 @@ // // Created by Bradley Austin Davis on 2015/06/12 // Copyright 2015 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -76,7 +77,7 @@ struct PoseData { } void update(const glm::mat4& resetMat) { - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { if (!vrPoses[i].bPoseIsValid) { continue; } @@ -87,7 +88,7 @@ struct PoseData { } void resetToInvalid() { - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { vrPoses[i].bPoseIsValid = false; } } diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 2c9eb296ab..3629698e11 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -1,9 +1,9 @@ // // ViveControllerManager.cpp -// input-plugins/src/input-plugins // // Created by Sam Gondelman on 6/29/15. // Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -19,10 +19,12 @@ #pragma warning( disable : 4334 ) #endif +#ifdef VIVE_PRO_EYE #include #include #include #include +#endif #ifdef _WIN32 #pragma warning( pop ) @@ -49,7 +51,7 @@ #include #include -#include +#include #include #include "OpenVrDisplayPlugin.h" @@ -60,13 +62,8 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); static const QString OPENVR_LAYOUT = QString("OpenVrConfiguration.qml"); -static const char* CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const quint64 CALIBRATION_TIMELAPSE = 1 * USECS_PER_SECOND; -static const char* MENU_PARENT = "Avatar"; -static const char* MENU_NAME = "Vive Controllers"; -static const char* MENU_PATH = "Avatar" ">" "Vive Controllers"; - static const int MIN_HEAD = 1; static const int MIN_PUCK_COUNT = 2; static const int MIN_FEET_AND_HIPS = 3; @@ -79,6 +76,7 @@ static const int SECOND_FOOT = 1; static const int HIP = 2; static const int CHEST = 3; +#ifdef VIVE_PRO_EYE enum ViveHandJointIndex { HAND = 0, THUMB_1, @@ -104,6 +102,7 @@ enum ViveHandJointIndex { Size }; +#endif const char* ViveControllerManager::NAME { "OpenVR" }; @@ -157,22 +156,7 @@ static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult) return result; } -static glm::mat4 calculateResetMat() { - auto chaperone = vr::VRChaperone(); - if (chaperone) { - float const UI_RADIUS = 1.0f; - float const UI_HEIGHT = 1.6f; - float const UI_Z_OFFSET = 0.5; - - float xSize, zSize; - chaperone->GetPlayAreaSize(&xSize, &zSize); - glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET); - - return glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos)); - } - return glm::mat4(); -} - +#ifdef VIVE_PRO_EYE class ViveProEyeReadThread : public QThread { public: ViveProEyeReadThread() { @@ -216,6 +200,7 @@ public: QMutex eyeDataMutex; EyeDataBuffer eyeDataBuffer; }; +#endif static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) { @@ -279,6 +264,10 @@ void ViveControllerManager::setConfigurationSettings(const QJsonObject configura _hmdDesktopTracking = configurationSettings["hmdDesktopTracking"].toBool(); } + if (configurationSettings.contains("eyeTrackingEnabled")) { + _eyeTrackingEnabled = configurationSettings["eyeTrackingEnabled"].toBool(); + } + _inputDevice->configureCalibrationSettings(configurationSettings); saveSettings(); } @@ -289,6 +278,7 @@ QJsonObject ViveControllerManager::configurationSettings() { QJsonObject configurationSettings = _inputDevice->configurationSettings(); configurationSettings["desktopMode"] = _desktopMode; configurationSettings["hmdDesktopTracking"] = _hmdDesktopTracking; + configurationSettings["eyeTrackingEnabled"] = _eyeTrackingEnabled; return configurationSettings; } @@ -328,7 +318,7 @@ bool areBothHandControllersActive(vr::IVRSystem*& system) { isHandControllerActive(system, vr::TrackedControllerRole_RightHand); } - +#ifdef VIVE_PRO_EYE void ViveControllerManager::enableGestureDetection() { if (_viveCameraHandTracker) { return; @@ -373,6 +363,7 @@ void ViveControllerManager::disableGestureDetection() { StopGestureDetection(); _viveCameraHandTracker = false; } +#endif bool ViveControllerManager::activate() { InputPlugin::activate(); @@ -394,6 +385,7 @@ bool ViveControllerManager::activate() { userInputMapper->registerDevice(_inputDevice); _registeredWithInputMapper = true; +#ifdef VIVE_PRO_EYE if (ViveSR::anipal::Eye::IsViveProEye()) { qDebug() << "Vive Pro eye-tracking detected"; @@ -414,6 +406,7 @@ bool ViveControllerManager::activate() { _viveProEyeReadThread->start(QThread::HighPriority); } } +#endif return true; } @@ -436,12 +429,14 @@ void ViveControllerManager::deactivate() { userInputMapper->removeDevice(_inputDevice->_deviceID); _registeredWithInputMapper = false; +#ifdef VIVE_PRO_EYE if (_viveProEyeReadThread) { _viveProEyeReadThread->quit = true; _viveProEyeReadThread->wait(); _viveProEyeReadThread = nullptr; ViveSR::anipal::Release(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE); } +#endif saveSettings(); } @@ -454,6 +449,7 @@ bool ViveControllerManager::isHeadControllerMounted() const { return activityLevel == vr::k_EDeviceActivityLevel_UserInteraction; } +#ifdef VIVE_PRO_EYE void ViveControllerManager::invalidateEyeInputs() { _inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false; _inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false; @@ -461,7 +457,6 @@ void ViveControllerManager::invalidateEyeInputs() { _inputDevice->_axisStateMap[controller::EYEBLINK_R].valid = false; } - void ViveControllerManager::updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { if (!isHeadControllerMounted()) { invalidateEyeInputs(); @@ -763,6 +758,7 @@ void ViveControllerManager::updateCameraHandTracker(float deltaTime, } _lastHandTrackerFrameIndex = handTrackerFrameIndex; } +#endif void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) { @@ -801,11 +797,14 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu _registeredWithInputMapper = true; } - if (_viveProEye) { +#ifdef VIVE_PRO_EYE + if (_viveProEye && _eyeTrackingEnabled) { updateEyeTracker(deltaTime, inputCalibrationData); } updateCameraHandTracker(deltaTime, inputCalibrationData); +#endif + } void ViveControllerManager::loadSettings() { @@ -821,6 +820,9 @@ void ViveControllerManager::loadSettings() { _inputDevice->_shoulderWidth = settings.value("shoulderWidth", QVariant(DEFAULT_SHOULDER_WIDTH)).toDouble(); _inputDevice->_outOfRangeDataStrategy = stringToOutOfRangeDataStrategy(settings.value("outOfRangeDataStrategy", QVariant(DEFAULT_OUT_OF_RANGE_STRATEGY)).toString()); } + + const bool DEFAULT_EYE_TRACKING_ENABLED = false; + _eyeTrackingEnabled = settings.value("eyeTrackingEnabled", QVariant(DEFAULT_EYE_TRACKING_ENABLED)).toBool(); } settings.endGroup(); } @@ -835,6 +837,8 @@ void ViveControllerManager::saveSettings() const { settings.setValue(QString("shoulderWidth"), _inputDevice->_shoulderWidth); settings.setValue(QString("outOfRangeDataStrategy"), outOfRangeDataStrategyToString(_inputDevice->_outOfRangeDataStrategy)); } + + settings.setValue(QString("eyeTrackingEnabled"), _eyeTrackingEnabled); } settings.endGroup(); } @@ -863,6 +867,9 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle if (_headsetName == "HTC") { _headsetName += " Vive"; } + if (oculusViaOpenVR()) { + _headsetName = "OpenVR"; // Enables calibration dialog to function when debugging using Oculus. + } } // While the keyboard is open, we defer strictly to the keyboard values if (isOpenVrKeyboardShown()) { @@ -879,7 +886,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, const controlle handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false); // collect poses for all generic trackers - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { + for (uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { handleTrackedObject(i, inputCalibrationData); handleHmd(i, inputCalibrationData); } @@ -954,8 +961,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHead = headObject["override"].toBool(); if (overrideHead) { _headConfig = HeadConfig::Puck; - _headPuckYOffset = headObject["Y"].toDouble() * CM_TO_M; - _headPuckZOffset = headObject["Z"].toDouble() * CM_TO_M; + _headPuckYOffset = (float)headObject["Y"].toDouble() * CM_TO_M; + _headPuckZOffset = (float)headObject["Z"].toDouble() * CM_TO_M; } else { _headConfig = HeadConfig::HMD; } @@ -964,8 +971,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso bool overrideHands = handsObject["override"].toBool(); if (overrideHands) { _handConfig = HandConfig::Pucks; - _handPuckYOffset = handsObject["Y"].toDouble() * CM_TO_M; - _handPuckZOffset = handsObject["Z"].toDouble() * CM_TO_M; + _handPuckYOffset = (float)handsObject["Y"].toDouble() * CM_TO_M; + _handPuckZOffset = (float)handsObject["Z"].toDouble() * CM_TO_M; } else { _handConfig = HandConfig::HandController; } @@ -999,8 +1006,8 @@ QJsonObject ViveControllerManager::InputDevice::configurationSettings() { configurationSettings["HMDHead"] = (_headConfig == HeadConfig::HMD); configurationSettings["handController"] = (_handConfig == HandConfig::HandController); configurationSettings["puckCount"] = (int)_validTrackedObjects.size(); - configurationSettings["armCircumference"] = (double)_armCircumference * M_TO_CM; - configurationSettings["shoulderWidth"] = (double)_shoulderWidth * M_TO_CM; + configurationSettings["armCircumference"] = (double)(_armCircumference * M_TO_CM); + configurationSettings["shoulderWidth"] = (double)(_shoulderWidth * M_TO_CM); configurationSettings["outOfRangeDataStrategy"] = outOfRangeDataStrategyToString(_outOfRangeDataStrategy); return configurationSettings; } @@ -1217,8 +1224,6 @@ bool ViveControllerManager::InputDevice::configureHead(const glm::mat4& defaultT bool ViveControllerManager::InputDevice::configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) { std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); int puckCount = (int)_validTrackedObjects.size(); - glm::vec3 headXAxis = getReferenceHeadXAxis(defaultToReferenceMat, inputCalibration.defaultHeadMat); - glm::vec3 headPosition = getReferenceHeadPosition(defaultToReferenceMat, inputCalibration.defaultHeadMat); if (_config == Config::None) { return true; } else if (_config == Config::Feet && puckCount >= MIN_PUCK_COUNT) { @@ -1316,8 +1321,6 @@ controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(const c } void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData) { - uint32_t poseIndex = controller::TRACKED_OBJECT_00 + deviceIndex; - if (_system->IsTrackedDeviceConnected(deviceIndex) && _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_HMD && _nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) { @@ -1491,11 +1494,11 @@ void ViveControllerManager::InputDevice::printDeviceTrackingResultChange(uint32_ } bool ViveControllerManager::InputDevice::checkForCalibrationEvent() { - auto& endOfMap = _buttonPressedMap.end(); - auto& leftTrigger = _buttonPressedMap.find(controller::LT); - auto& rightTrigger = _buttonPressedMap.find(controller::RT); - auto& leftAppButton = _buttonPressedMap.find(LEFT_APP_MENU); - auto& rightAppButton = _buttonPressedMap.find(RIGHT_APP_MENU); + auto endOfMap = _buttonPressedMap.end(); + auto leftTrigger = _buttonPressedMap.find(controller::LT); + auto rightTrigger = _buttonPressedMap.find(controller::RT); + auto leftAppButton = _buttonPressedMap.find(LEFT_APP_MENU); + auto rightAppButton = _buttonPressedMap.find(RIGHT_APP_MENU); return ((leftTrigger != endOfMap && leftAppButton != endOfMap) && (rightTrigger != endOfMap && rightAppButton != endOfMap)); } @@ -1846,10 +1849,74 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu * Hipsnumber{@link Pose}Hips pose. * Spine2number{@link Pose}Spine2 pose. * Headnumber{@link Pose}Head pose. + * LeftEyenumber{@link Pose}Left eye pose. + * RightEyenumber{@link Pose}Right eye pose. + * EyeBlink_LnumbernumberLeft eyelid blink. + * EyeBlink_RnumbernumberRight eyelid blink. * LeftArmnumber{@link Pose}Left arm pose. * RightArmnumber{@link Pose}Right arm pose * LeftHandnumber{@link Pose}Left hand pose. + * LeftHandThumb1number{@link Pose}Left thumb 1 finger joint pose. + * LeftHandThumb2number{@link Pose}Left thumb 2 finger joint pose. + * LeftHandThumb3number{@link Pose}Left thumb 3 finger joint pose. + * LeftHandThumb4number{@link Pose}Left thumb 4 finger joint pose. + * LeftHandIndex1number{@link Pose}Left index 1 finger joint pose. + * LeftHandIndex2number{@link Pose}Left index 2 finger joint pose. + * LeftHandIndex3number{@link Pose}Left index 3 finger joint pose. + * LeftHandIndex4number{@link Pose}Left index 4 finger joint pose. + * LeftHandMiddle1number{@link Pose}Left middle 1 finger joint pose. + * + * LeftHandMiddle2number{@link Pose}Left middle 2 finger joint pose. + * + * LeftHandMiddle3number{@link Pose}Left middle 3 finger joint pose. + * + * LeftHandMiddle4number{@link Pose}Left middle 4 finger joint pose. + * + * LeftHandRing1number{@link Pose}Left ring 1 finger joint pose. + * LeftHandRing2number{@link Pose}Left ring 2 finger joint pose. + * LeftHandRing3number{@link Pose}Left ring 3 finger joint pose. + * LeftHandRing4number{@link Pose}Left ring 4 finger joint pose. + * LeftHandPinky1number{@link Pose}Left pinky 1 finger joint pose. + * LeftHandPinky2number{@link Pose}Left pinky 2 finger joint pose. + * LeftHandPinky3number{@link Pose}Left pinky 3 finger joint pose. + * LeftHandPinky4number{@link Pose}Left pinky 4 finger joint pose. * RightHandnumber{@link Pose}Right hand pose. + * RightHandThumb1number{@link Pose}Right thumb 1 finger joint pose. + * + * RightHandThumb2number{@link Pose}Right thumb 2 finger joint pose. + * + * RightHandThumb3number{@link Pose}Right thumb 3 finger joint pose. + * + * RightHandThumb4number{@link Pose}Right thumb 4 finger joint pose. + * + * RightHandIndex1number{@link Pose}Right index 1 finger joint pose. + * + * RightHandIndex2number{@link Pose}Right index 2 finger joint pose. + * + * RightHandIndex3number{@link Pose}Right index 3 finger joint pose. + * + * RightHandIndex4number{@link Pose}Right index 4 finger joint pose. + * + * RightHandMiddle1number{@link Pose}Right middle 1 finger joint pose. + * + * RightHandMiddle2number{@link Pose}Right middle 2 finger joint pose. + * + * RightHandMiddle3number{@link Pose}Right middle 3 finger joint pose. + * + * RightHandMiddle4number{@link Pose}Right middle 4 finger joint pose. + * + * RightHandRing1number{@link Pose}Right ring 1 finger joint pose. + * RightHandRing2number{@link Pose}Right ring 2 finger joint pose. + * RightHandRing3number{@link Pose}Right ring 3 finger joint pose. + * RightHandRing4number{@link Pose}Right ring 4 finger joint pose. + * RightHandPinky1number{@link Pose}Right pinky 1 finger joint pose. + * + * RightHandPinky2number{@link Pose}Right pinky 2 finger joint pose. + * + * RightHandPinky3number{@link Pose}Right pinky 3 finger joint pose. + * + * RightHandPinky4number{@link Pose}Right pinky 4 finger joint pose. + * * Trackers * TrackedObject00number{@link Pose}Tracker 0 pose. * TrackedObject01number{@link Pose}Tracker 1 pose. diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 714be87842..956b2b5eaf 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -1,9 +1,9 @@ // // ViveControllerManager.h -// input-plugins/src/input-plugins // // Created by Sam Gondelman on 6/29/15. // Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -25,12 +25,18 @@ #include #include "OpenVrHelpers.h" +#ifdef Q_OS_WIN +#define VIVE_PRO_EYE +#endif + using PuckPosePair = std::pair; namespace vr { class IVRSystem; } + +#ifdef VIVE_PRO_EYE class ViveProEyeReadThread; class EyeDataBuffer { @@ -45,7 +51,7 @@ public: float leftEyeOpenness { 0.0f }; float rightEyeOpenness { 0.0f }; }; - +#endif class ViveControllerManager : public InputPlugin { @@ -66,18 +72,22 @@ public: bool isHeadController() const override { return true; } bool isHeadControllerMounted() const; +#ifdef VIVE_PRO_EYE void enableGestureDetection(); void disableGestureDetection(); +#endif bool activate() override; void deactivate() override; - QString getDeviceName() { return QString::fromStdString(_inputDevice->_headsetName); } + QString getDeviceName() override { return QString::fromStdString(_inputDevice->_headsetName); } void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } +#ifdef VIVE_PRO_EYE void invalidateEyeInputs(); void updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData); void updateCameraHandTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData); +#endif void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override; virtual void saveSettings() const override; @@ -252,6 +262,9 @@ private: vr::IVRSystem* _system { nullptr }; std::shared_ptr _inputDevice { std::make_shared(_system) }; + bool _eyeTrackingEnabled{ false }; + +#ifdef VIVE_PRO_EYE bool _viveProEye { false }; std::shared_ptr _viveProEyeReadThread; EyeDataBuffer _prevEyeData; @@ -268,6 +281,7 @@ private: void trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4, controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2, controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4); +#endif static const char* NAME; }; diff --git a/screenshare/packager.js b/screenshare/packager.js index 7a0baebaf0..05bda9af71 100644 --- a/screenshare/packager.js +++ b/screenshare/packager.js @@ -26,8 +26,8 @@ if (osType == "Darwin") { options["app-bundle-id"] = "com.highfidelity.hifi-screenshare"; } else if (osType == "Windows_NT") { options["version-string"] = { - CompanyName: "High Fidelity, Inc.", - FileDescription: "High Fidelity Screenshare", + CompanyName: "Vircadia", + FileDescription: "Vircadia Screenshare", ProductName: NAME, OriginalFilename: NAME + ".exe" } @@ -47,4 +47,3 @@ packager(options) console.error("There was an error writing the packaged console: " + error.message); process.exit(1); }); - \ No newline at end of file diff --git a/scripts/communityModules/chat/FloofChat.html b/scripts/communityScripts/chat/FloofChat.html similarity index 80% rename from scripts/communityModules/chat/FloofChat.html rename to scripts/communityScripts/chat/FloofChat.html index a1e84e132f..b493b05090 100644 --- a/scripts/communityModules/chat/FloofChat.html +++ b/scripts/communityScripts/chat/FloofChat.html @@ -12,6 +12,7 @@ + @@ -28,11 +29,19 @@
+ +
+ +
@@ -46,6 +55,7 @@ \ No newline at end of file diff --git a/scripts/system/inventory/dist/inventory-a-msg.svg b/scripts/system/inventory/dist/inventory-a-msg.svg new file mode 100644 index 0000000000..480a3fdd5d --- /dev/null +++ b/scripts/system/inventory/dist/inventory-a-msg.svg @@ -0,0 +1 @@ + diff --git a/scripts/system/inventory/dist/inventory-a.svg b/scripts/system/inventory/dist/inventory-a.svg new file mode 100644 index 0000000000..c53d21722c --- /dev/null +++ b/scripts/system/inventory/dist/inventory-a.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/scripts/system/inventory/dist/inventory-i-msg.svg b/scripts/system/inventory/dist/inventory-i-msg.svg new file mode 100644 index 0000000000..95856910fa --- /dev/null +++ b/scripts/system/inventory/dist/inventory-i-msg.svg @@ -0,0 +1 @@ + diff --git a/scripts/system/inventory/dist/inventory-i.svg b/scripts/system/inventory/dist/inventory-i.svg new file mode 100644 index 0000000000..c5ec3d8cc3 --- /dev/null +++ b/scripts/system/inventory/dist/inventory-i.svg @@ -0,0 +1 @@ + diff --git a/scripts/system/inventory/dist/inventory.js b/scripts/system/inventory/dist/inventory.js new file mode 100644 index 0000000000..12ecba1546 --- /dev/null +++ b/scripts/system/inventory/dist/inventory.js @@ -0,0 +1,299 @@ +// +// inventory.js +// +// Created by kasenvr@gmail.com on 2 Apr 2020 +// Copyright 2020 Vircadia and contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +/* global AvatarList Clipboard console Controller Entities location Messages MyAvatar Script ScriptDiscoveryService Settings +Tablet Vec3 Window */ + +(function () { // BEGIN LOCAL_SCOPE + "use strict"; + var AppUi = Script.require('appUi'); + var ui; + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + + // VARIABLES + var inventoryDataSettingString = "inventoryApp.data"; + var inventoryData; + + var inventorySettingsString = "inventoryApp.settings"; + var inventorySettings; + + var RECEIVING_ITEM_QUEUE_LIMIT = 5; + var receivingItemQueue = []; + + var NEARBY_USERS_SEARCH_RADIUS = 25; + + + // APP EVENT AND MESSAGING ROUTING + + function onWebAppEventReceived(event) { + var eventJSON = JSON.parse(event); + if (eventJSON.app === "inventory") { // This is our web app! + // print("inventory.js received a web event: " + event); + + if (eventJSON.command === "ready") { + initializeInventoryApp(); + } + + if (eventJSON.command === "web-to-script-inventory") { + receiveInventory(eventJSON.data); + } + + if (eventJSON.command === "web-to-script-settings") { + receiveSettings(eventJSON.data); + } + + if (eventJSON.command === "use-item") { + useItem(eventJSON.data); + } + + if (eventJSON.command === "share-item") { + shareItem(eventJSON.data); + } + + if (eventJSON.command === "web-to-script-request-nearby-users") { + sendNearbyUsers(); + } + + if (eventJSON.command === "web-to-script-request-receiving-item-queue") { + sendReceivingItemQueue(); + } + + if (eventJSON.command === "web-to-script-update-receiving-item-queue") { + updateReceivingItemQueue(eventJSON.data); + } + + } + } + + tablet.webEventReceived.connect(onWebAppEventReceived); + + function sendToWeb(command, data) { + var dataToSend = { + "app": "inventory", + "command": command, + "data": data + }; + + tablet.emitScriptEvent(JSON.stringify(dataToSend)); + } + + var inventoryMessagesChannel = "com.vircadia.inventory"; + + function onMessageReceived(channel, message, sender, localOnly) { + if (channel === inventoryMessagesChannel) { + var messageJSON = JSON.parse(message); + // Window.alert("Passed 0 " + messageJSON.recipient + " vs " + MyAvatar.sessionUUID); + if (messageJSON.command === "share-item" + && messageJSON.recipient === MyAvatar.sessionUUID) { // We are receiving an item. + // Window.alert("Passed 1 " + messageJSON.recipient + " vs " + MyAvatar.sessionUUID); + pushReceivedItemToQueue(sender, messageJSON.type, messageJSON.name, messageJSON.url); + } + } + // print("Message received:"); + // print("- channel: " + channel); + // print("- message: " + message); + // print("- sender: " + sender); + // print("- localOnly: " + localOnly); + } + + function sendMessage(dataToSend) { + Messages.sendMessage(inventoryMessagesChannel, JSON.stringify(dataToSend)); + } + + // END APP EVENT AND MESSAGING ROUTING + + // SEND AND RECEIVE INVENTORY STATE + + function receiveInventory(receivedInventoryData) { + inventoryData = receivedInventoryData; + saveInventory(); + } + + function sendInventory() { + sendToWeb("script-to-web-inventory", inventoryData); + } + + // END SEND AND RECEIVE INVENTORY STATE + + // SEND AND RECEIVE SETTINGS STATE + + function receiveSettings(receivedSettingsData) { + inventorySettings = receivedSettingsData; + saveSettings(); + } + + function sendSettings() { + sendToWeb("script-to-web-settings", inventorySettings); + } + + // END SEND AND RECEIVE SETTINGS STATE + + function saveInventory() { + Settings.setValue(inventoryDataSettingString, inventoryData); + } + + function loadInventory() { + inventoryData = Settings.getValue(inventoryDataSettingString); + } + + function saveSettings() { + Settings.setValue(inventorySettingsString, inventorySettings); + } + + function loadSettings() { + inventorySettings = Settings.getValue(inventorySettingsString); + } + + function pushReceivedItemToQueue(senderUUID, type, name, url) { + console.info("Receiving an item:", name, "from:", senderUUID); + var getAvatarData = AvatarList.getAvatar(senderUUID); + var senderName = getAvatarData.sessionDisplayName; + var senderDistance = Vec3.distance(MyAvatar.position, getAvatarData.position); + + var packageRequest = { + "senderUUID": senderUUID, + "senderName": senderName, + "senderDistance": senderDistance, + "data": { + "type": type, + "name": name, + "url": url + } + }; + + if (receivingItemQueue.length === RECEIVING_ITEM_QUEUE_LIMIT) { + receivingItemQueue = receivingItemQueue.slice(1, RECEIVING_ITEM_QUEUE_LIMIT); + } + + receivingItemQueue.push(packageRequest); + ui.messagesWaiting(receivingItemQueue.length > 0); + } + + function sendReceivingItemQueue() { + sendToWeb("script-to-web-receiving-item-queue", receivingItemQueue); + } + + function updateReceivingItemQueue(data) { + receivingItemQueue = data; + ui.messagesWaiting(receivingItemQueue.length > 0); + } + + function sendNearbyUsers() { + var nearbyUsers = AvatarList.getAvatarsInRange(MyAvatar.position, NEARBY_USERS_SEARCH_RADIUS); + var nearbyUsersToSend = []; + + nearbyUsers.forEach(function(user) { + var objectToWrite; + var aviDetails = AvatarList.getAvatar(user); + var aviName = aviDetails.displayName; + var aviDistance = Vec3.distance(MyAvatar.position, aviDetails.position); + // Window.alert("aviName" + aviName + "user" + user + "MyAvatar.sessionUUID" + MyAvatar.sessionUUID); + if (user !== MyAvatar.sessionUUID + || Controller.getValue(Controller.Hardware.Keyboard.Shift)) { // Don't add ourselves to the list! + objectToWrite = { "name": aviName, "distance": aviDistance, "uuid": user }; + nearbyUsersToSend.push(objectToWrite); + } + }); + + sendToWeb("script-to-web-nearby-users", nearbyUsersToSend); + } + + function useItem(item) { + + //TODO: Add animation support for avatars...? + + // Convert the item.type before checking it... + item.type = item.type.toUpperCase(); + + // Depending on the type, we decide how to load this item. + if (item.type === "SCRIPT") { + ScriptDiscoveryService.loadScript(item.url, true, false, false, true, false); + } + + if (item.type === "MODEL") { + Entities.addEntity({ + type: "Model", + position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1.5 })), + rotation: MyAvatar.orientation, + modelURL: item.url, + collisionless: true + }); + } + + if (item.type === "AVATAR") { + MyAvatar.useFullAvatarURL(item.url); + } + + if (item.type === "PLACE") { + location.handleLookupString(item.url, true); + } + + if (item.type === "JSON") { + var jsonToLoad = item.url; + if (jsonToLoad) { + if (Clipboard.importEntities(jsonToLoad)) { + Clipboard.pasteEntities( + Vec3.sum( + MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -1.5 }) + ) + ); + } + } + } + + if (item.type === "UNKNOWN") { + // We don't know how to handle this yet. + Window.alert("Unknown item type, unable to use."); + } + } + + function shareItem(data) { + data.command = "share-item"; + sendMessage(data); + } + + function initializeInventoryApp() { + sendSettings(); + sendInventory(); + sendReceivingItemQueue(); + } + + function onOpened() { + } + + function onClosed() { + } + + function startup() { + + loadInventory(); + loadSettings(); + + Messages.messageReceived.connect(onMessageReceived); + Messages.subscribe(inventoryMessagesChannel); + + ui = new AppUi({ + buttonName: "INVENTORY", + home: Script.resolvePath("index.html"), + graphicsDirectory: Script.resolvePath("./"), // Where your button icons are located + onOpened: onOpened, + onClosed: onClosed + }); + } + + startup(); + + Script.scriptEnding.connect(function () { + Messages.messageReceived.disconnect(onMessageReceived); + Messages.unsubscribe(inventoryMessagesChannel); + }); + +}()); // END LOCAL_SCOPE \ No newline at end of file diff --git a/scripts/system/inventory/dist/js/app.a3555a80.js b/scripts/system/inventory/dist/js/app.a3555a80.js new file mode 100644 index 0000000000..b902a5e4f5 --- /dev/null +++ b/scripts/system/inventory/dist/js/app.a3555a80.js @@ -0,0 +1,2 @@ +(function(e){function t(t){for(var r,s,l=t[0],n=t[1],d=t[2],u=0,m=[];u0,expression:"receivingItemQueueLength > 0"}]},[e._v(" A list of all items being received currently. ")]),i("v-card-text",{directives:[{name:"show",rawName:"v-show",value:0===e.receivingItemQueueLength,expression:"receivingItemQueueLength === 0"}]},[e._v(" There are currently no items in your inbox. ")]),i("v-card-actions",[i("v-list",{directives:[{name:"show",rawName:"v-show",value:e.receivingItemQueueLength>0,expression:"receivingItemQueueLength > 0"}],staticClass:"pt-5",attrs:{nav:"","max-width":"370"}},e._l(e.receivingItemsDialog.data.receivingItemQueue,(function(t){return i("v-list-item",{key:t.data.uuid,attrs:{"two-line":""}},[i("v-list-item-content",[i("v-list-item-title",[e._v(e._s(t.data.name))]),i("v-list-item-subtitle",[e._v("Sent by "+e._s(t.senderName))]),i("v-list-item-subtitle",[e._v("Distance: "+e._s(t.senderDistance.toFixed(1))+"m")])],1),i("v-btn",{attrs:{color:"success"},on:{click:function(i){return e.acceptReceivingItem(t)}}},[i("v-icon",[e._v("mdi-plus")])],1),i("v-btn",{attrs:{text:"",color:"red"},on:{click:function(i){return e.removeReceivingItem(t.data.uuid)}}},[i("v-icon",[e._v("mdi-minus")])],1)],1)})),1)],1)],1)],1),i("v-dialog",{attrs:{"max-width":"290"},model:{value:e.removeDialogStore.show,callback:function(t){e.$set(e.removeDialogStore,"show",t)},expression:"removeDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Remove Item")]),i("v-card-text",[e._v(" Are you sure you want to delete this item from your inventory? ")]),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"blue"},on:{click:function(t){e.removeDialogStore.show=!1}}},[e._v(" No ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.removeDialogStore.show=!1,e.removeItem(e.$store.state.removeDialog.uuid)}}},[e._v(" Yes ")])],1)],1)],1),i("v-dialog",{attrs:{"max-width":"290"},model:{value:e.removeFolderDialogStore.show,callback:function(t){e.$set(e.removeFolderDialogStore,"show",t)},expression:"removeFolderDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Remove Folder")]),i("v-card-text",[e._v(" Are you sure you want to delete this folder "),i("b",[e._v("and")]),e._v(" all items within from your inventory? ")]),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"blue"},on:{click:function(t){e.removeFolderDialogStore.show=!1}}},[e._v(" No ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.removeFolderDialogStore.show=!1,e.removeFolder(e.$store.state.removeFolderDialog.uuid)}}},[e._v(" Yes ")])],1)],1)],1),i("v-dialog",{attrs:{"max-width":"380"},model:{value:e.editDialogStore.show,callback:function(t){e.$set(e.editDialogStore,"show",t)},expression:"editDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Edit Item")]),i("v-form",{ref:"editForm",attrs:{"lazy-validation":!1},model:{value:e.editDialogStore.valid,callback:function(t){e.$set(e.editDialogStore,"valid",t)},expression:"editDialogStore.valid"}},[i("v-select",{staticClass:"my-2",attrs:{items:e.$store.state.supportedItemTypes,rules:[function(e){return!!e||"Type is required."}],label:"Item Type",outlined:""},model:{value:e.editDialogStore.data.type,callback:function(t){e.$set(e.editDialogStore.data,"type",t)},expression:"editDialogStore.data.type"}}),i("v-text-field",{staticClass:"px-2",attrs:{label:"Name",rules:[function(e){return!!e||"Name is required."}],required:""},model:{value:e.editDialogStore.data.name,callback:function(t){e.$set(e.editDialogStore.data,"name",t)},expression:"editDialogStore.data.name"}}),i("v-select",{staticClass:"my-2",attrs:{items:e.folderList,"item-text":"name","item-value":"uuid",label:"Folder",outlined:""},model:{value:e.editDialogStore.data.folder,callback:function(t){e.$set(e.editDialogStore.data,"folder",t)},expression:"editDialogStore.data.folder"}}),i("v-text-field",{staticClass:"px-2",attrs:{label:"URL",rules:[function(e){return!!e||"URL is required."}],required:""},model:{value:e.editDialogStore.data.url,callback:function(t){e.$set(e.editDialogStore.data,"url",t)},expression:"editDialogStore.data.url"}}),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.editDialogStore.show=!1}}},[e._v(" Cancel ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"blue",disabled:!e.$store.state.editDialog.valid},on:{click:function(t){e.editDialogStore.show=!1,e.editItem(e.$store.state.editDialog.uuid)}}},[e._v(" Done ")])],1)],1)],1)],1),i("v-dialog",{attrs:{"max-width":"380"},model:{value:e.editFolderDialogStore.show,callback:function(t){e.$set(e.editFolderDialogStore,"show",t)},expression:"editFolderDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Edit Folder")]),i("v-form",{ref:"editFolderForm",attrs:{"lazy-validation":!1},model:{value:e.editFolderDialogStore.valid,callback:function(t){e.$set(e.editFolderDialogStore,"valid",t)},expression:"editFolderDialogStore.valid"}},[i("v-text-field",{staticClass:"px-2",attrs:{label:"Name",rules:[function(e){return!!e||"Name is required."}],required:""},model:{value:e.editFolderDialogStore.data.name,callback:function(t){e.$set(e.editFolderDialogStore.data,"name",t)},expression:"editFolderDialogStore.data.name"}}),i("v-select",{staticClass:"my-2",attrs:{items:e.folderList,"item-text":"name","item-value":"uuid",label:"Parent Folder",outlined:""},model:{value:e.editFolderDialogStore.data.folder,callback:function(t){e.$set(e.editFolderDialogStore.data,"folder",t)},expression:"editFolderDialogStore.data.folder"}}),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.editFolderDialogStore.show=!1}}},[e._v(" Cancel ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"blue",disabled:!e.$store.state.editFolderDialog.valid},on:{click:function(t){e.editFolderDialogStore.show=!1,e.editFolder(e.$store.state.editFolderDialog.data.uuid)}}},[e._v(" Done ")])],1)],1)],1)],1),i("v-dialog",{attrs:{"max-width":"380"},model:{value:e.createFolderDialogStore.show,callback:function(t){e.$set(e.createFolderDialogStore,"show",t)},expression:"createFolderDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Create Folder")]),i("v-card-text",[e._v(" Enter the name of the folder. ")]),i("v-form",{ref:"createFolderForm",attrs:{"lazy-validation":!1},model:{value:e.createFolderDialogStore.valid,callback:function(t){e.$set(e.createFolderDialogStore,"valid",t)},expression:"createFolderDialogStore.valid"}},[i("v-text-field",{staticClass:"px-2",attrs:{label:"Name",rules:[function(e){return!!e||"Name is required."}],required:""},model:{value:e.createFolderDialogStore.data.name,callback:function(t){e.$set(e.createFolderDialogStore.data,"name",t)},expression:"createFolderDialogStore.data.name"}}),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.createFolderDialogStore.show=!1}}},[e._v(" Cancel ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"blue",disabled:!e.$store.state.createFolderDialog.valid},on:{click:function(t){e.createFolderDialogStore.show=!1,e.createFolder(e.$store.state.createFolderDialog.data.name)}}},[e._v(" Create ")])],1)],1)],1)],1),i("v-dialog",{attrs:{"max-width":"380"},model:{value:e.addDialogStore.show,callback:function(t){e.$set(e.addDialogStore,"show",t)},expression:"addDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Add Item")]),i("v-form",{ref:"addForm",attrs:{"lazy-validation":!1},model:{value:e.addDialogStore.valid,callback:function(t){e.$set(e.addDialogStore,"valid",t)},expression:"addDialogStore.valid"}},[i("v-card-text",[e._v(" Enter the name of the item. ")]),i("v-text-field",{staticClass:"px-2",attrs:{label:"Name",rules:[function(e){return!!e||"Name is required."}],required:""},model:{value:e.addDialogStore.data.name,callback:function(t){e.$set(e.addDialogStore.data,"name",t)},expression:"addDialogStore.data.name"}}),i("v-card-text",[e._v(" Select a folder (optional). ")]),i("v-select",{staticClass:"my-2",attrs:{items:e.folderList,label:"Folder",outlined:"","item-text":"name","item-value":"uuid"},model:{value:e.addDialogStore.data.folder,callback:function(t){e.$set(e.addDialogStore.data,"folder",t)},expression:"addDialogStore.data.folder"}}),i("v-card-text",[e._v(" Enter the URL of the item. ")]),i("v-text-field",{staticClass:"px-2",attrs:{label:"URL",rules:[function(e){return!!e||"URL is required."}],required:""},model:{value:e.addDialogStore.data.url,callback:function(t){e.$set(e.addDialogStore.data,"url",t)},expression:"addDialogStore.data.url"}}),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.addDialogStore.show=!1}}},[e._v(" Cancel ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"blue",disabled:!e.$store.state.addDialog.valid},on:{click:function(t){e.addDialogStore.show=!1,e.addItem(e.$store.state.addDialog.data.name,e.$store.state.addDialog.data.folder,e.$store.state.addDialog.data.url)}}},[e._v(" Add ")])],1)],1)],1)],1),i("v-dialog",{attrs:{"max-width":"380",persistent:""},model:{value:e.receiveDialogStore.show,callback:function(t){e.$set(e.receiveDialogStore,"show",t)},expression:"receiveDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Receiving Item")]),i("v-card-text",[i("b",[e._v(e._s(e.$store.state.receiveDialog.data.userDisplayName)+" sent you an item.")]),e._v(" "),i("br"),i("i",{staticClass:"caption"},[e._v("User UUID: "+e._s(e.$store.state.receiveDialog.data.userUUID))])]),i("v-form",{ref:"receiveForm",attrs:{"lazy-validation":!1},model:{value:e.receiveDialogStore.valid,callback:function(t){e.$set(e.receiveDialogStore,"valid",t)},expression:"receiveDialogStore.valid"}},[i("v-text-field",{staticClass:"px-2",attrs:{label:"Type",rules:[function(e){return!!e||"Type is required."}],required:""},model:{value:e.receiveDialogStore.data.type,callback:function(t){e.$set(e.receiveDialogStore.data,"type",t)},expression:"receiveDialogStore.data.type"}}),i("v-text-field",{staticClass:"px-2",attrs:{label:"Name",rules:[function(e){return!!e||"Name is required."}],required:""},model:{value:e.receiveDialogStore.data.name,callback:function(t){e.$set(e.receiveDialogStore.data,"name",t)},expression:"receiveDialogStore.data.name"}}),i("v-card-text",[e._v(" Select a folder (optional). ")]),i("v-select",{staticClass:"my-2",attrs:{items:e.folderList,label:"Folder",outlined:"","item-text":"name","item-value":"uuid"},model:{value:e.receiveDialogStore.data.folder,callback:function(t){e.$set(e.receiveDialogStore.data,"folder",t)},expression:"receiveDialogStore.data.folder"}}),i("v-text-field",{staticClass:"px-2",attrs:{label:"URL",rules:[function(e){return!!e||"URL is required."}],required:""},model:{value:e.receiveDialogStore.data.url,callback:function(t){e.$set(e.receiveDialogStore.data,"url",t)},expression:"receiveDialogStore.data.url"}}),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.receiveDialogStore.show=!1}}},[e._v(" Reject ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"blue",disabled:!e.$store.state.receiveDialog.valid},on:{click:function(t){e.receiveDialogStore.show=!1,e.confirmItemReceipt()}}},[e._v(" Accept ")])],1)],1)],1)],1),i("v-dialog",{attrs:{"max-width":"380",persistent:""},model:{value:e.shareDialogStore.show,callback:function(t){e.$set(e.shareDialogStore,"show",t)},expression:"shareDialogStore.show"}},[i("v-card",[i("v-card-title",{staticClass:"headline"},[e._v("Share Item")]),i("v-card-text",[e._v(" Select a user to send this item to. ")]),i("v-form",{ref:"shareForm",staticClass:"px-2",attrs:{"lazy-validation":!1},model:{value:e.shareDialogStore.valid,callback:function(t){e.$set(e.shareDialogStore,"valid",t)},expression:"shareDialogStore.valid"}},[i("v-select",{attrs:{items:e.nearbyUsers,"item-value":"uuid",rules:[function(e){return!!e||"A recipient is required"}],label:"Nearby Users",required:""},scopedSlots:e._u([{key:"item",fn:function(t){return[i("i",{staticStyle:{color:"grey","margin-right":"5px"}},[e._v(e._s(t.item.distance.toFixed(1))+"m")]),e._v(" "+e._s(t.item.name)+" ")]}},{key:"selection",fn:function(t){return[i("i",{staticStyle:{color:"grey","margin-right":"5px"}},[e._v(e._s(t.item.distance.toFixed(1))+"m")]),e._v(" "+e._s(t.item.name)+" ")]}}]),model:{value:e.shareDialogStore.data.recipient,callback:function(t){e.$set(e.shareDialogStore.data,"recipient",t)},expression:"shareDialogStore.data.recipient"}}),i("v-text-field",{staticClass:"px-2",attrs:{label:"URL",rules:[function(e){return!!e||"URL is required."}],required:""},model:{value:e.shareDialogStore.data.url,callback:function(t){e.$set(e.shareDialogStore.data,"url",t)},expression:"shareDialogStore.data.url"}}),i("v-card-actions",[i("v-btn",{staticClass:"px-3",attrs:{color:"red"},on:{click:function(t){e.shareDialogStore.show=!1}}},[e._v(" Cancel ")]),i("v-spacer"),i("v-btn",{staticClass:"px-3",attrs:{color:"blue",disabled:!e.$store.state.shareDialog.valid},on:{click:function(t){e.shareDialogStore.show=!1,e.shareItem(e.$store.state.shareDialog.data.uuid)}}},[e._v(" Send ")])],1)],1)],1)],1)],1)},s=[],l=(i("99af"),i("4160"),i("a15b"),i("a434"),i("b0c0"),i("d3b7"),i("ac1f"),i("3ca3"),i("466d"),i("159b"),i("ddb0"),i("2b3d"),new a["a"]),n=function(){var e=this,t=e.$createElement,i=e._self._c||t;return i("draggable",{attrs:{group:e.options,list:e.itemsForIterator,handle:".handle"}},e._l(e.itemsForIterator,(function(t){return i("v-item-group",{key:t.uuid},[t.items?i("v-list-group",{staticClass:"top-level-folder",scopedSlots:e._u([{key:"activator",fn:function(){return[i("v-list-item",{staticClass:"mx-auto",attrs:{"one-line":"","max-width":"344",outlined:""}},[i("v-icon",{staticClass:"folder-icon",attrs:{color:"teal"}},[e._v("mdi-folder-settings")]),e._v(" "+e._s(t.name)+" ")],1)]},proxy:!0}],null,!0)},[i("div",{staticClass:"text-center my-2"},[i("v-btn",{staticClass:"mx-1 folder-button",attrs:{medium:"",tile:"",color:"purple"},on:{click:function(i){e.editFolderDialogStore.data.uuid=t.uuid,e.editFolderDialogStore.data.name=t.name,e.editFolderDialogStore.show=!0}}},[i("v-icon",[e._v("mdi-pencil")])],1),i("v-btn",{staticClass:"mx-1 folder-button",attrs:{medium:"",tile:"",color:"red"},on:{click:function(i){e.removeFolderDialogStore.show=!0,e.removeFolderDialogStore.uuid=t.uuid}}},[i("v-icon",[e._v("mdi-minus")])],1),i("v-menu",{attrs:{bottom:"",left:""},scopedSlots:e._u([{key:"activator",fn:function(t){var r=t.on;return[i("v-btn",e._g({staticClass:"mx-1 folder-button",attrs:{medium:"",tile:"",color:"blue"}},r),[i("v-icon",[e._v("mdi-sort")])],1)]}}],null,!0)},[i("v-list",{attrs:{color:"grey darken-3"}},[i("v-list-item",{on:{click:function(i){return e.sortFolder(t.uuid,"az")}}},[i("v-list-item-title",[e._v("A-Z")]),i("v-list-item-action",[i("v-icon",{attrs:{large:""}},[e._v("mdi-sort-alphabetical-ascending")])],1)],1),i("v-list-item",{on:{click:function(i){return e.sortFolder(t.uuid,"za")}}},[i("v-list-item-title",[e._v("Z-A")]),i("v-list-item-action",[i("v-icon",{attrs:{large:""}},[e._v("mdi-sort-alphabetical-descending")])],1)],1)],1)],1)],1),i("v-container",{attrs:{fluid:""}},[i("itemiterator",{key:t.uuid,attrs:{itemsForIterator:t.items}})],1)],1):i("v-list-item",{staticClass:"mx-auto draggable-card",attrs:{"one-line":"","max-width":"344",outlined:""}},[i("div",{staticClass:"handle pa-2"},[i("v-icon",{attrs:{color:"orange darken-2"}},[e._v("mdi-square-medium-outline")])],1),i("v-list-item-content",{staticClass:"pb-1 pt-2 pl-4"},[i("div",{directives:[{name:"show",rawName:"v-show",value:e.settings.displayDensity.size>0,expression:"settings.displayDensity.size > 0"}],staticClass:"overline",staticStyle:{"font-size":"0.825rem !important"}},[e._v(e._s(t.type))]),i("v-list-item-title",{staticClass:"subtitle-1 mb-1"},[e._v(e._s(t.name))]),i("v-list-item-subtitle",{directives:[{name:"show",rawName:"v-show",value:2==e.settings.displayDensity.size,expression:"settings.displayDensity.size == 2"}]},[e._v(e._s(t.url))])],1),i("v-menu",{attrs:{bottom:"",left:""},scopedSlots:e._u([{key:"activator",fn:function(r){var a=r.on;return[i("v-btn",e._g({directives:[{name:"show",rawName:"v-show",value:e.settings.displayDensity.size>=1,expression:"settings.displayDensity.size >= 1"}],style:{backgroundColor:e.getIconColor(t.type)},attrs:{medium:"",fab:"",dark:""}},a),[i("v-icon",[e._v(e._s(e.getIcon(t.type)))])],1),i("v-btn",e._g({directives:[{name:"show",rawName:"v-show",value:e.settings.displayDensity.size<1,expression:"settings.displayDensity.size < 1"}],style:{backgroundColor:e.getIconColor(t.type)},attrs:{small:"",fab:"",dark:""}},a),[i("v-icon",[e._v(e._s(e.getIcon(t.type)))])],1)]}}],null,!0)},[i("v-list",{attrs:{color:"grey darken-3"}},[i("v-list-item",{on:{click:function(i){return e.sendEvent("use-item",{type:t.type,url:t.url})}}},[i("v-list-item-title",[e._v("Use")]),i("v-list-item-action",[i("v-icon",[e._v("mdi-play")])],1)],1),i("v-list-item",{on:{click:function(i){e.editDialogStore.show=!0,e.editDialogStore.uuid=t.uuid,e.editDialogStore.data.type=t.type.toUpperCase(),e.editDialogStore.data.folder=null,e.editDialogStore.data.name=t.name,e.editDialogStore.data.url=t.url}}},[i("v-list-item-title",[e._v("Edit")]),i("v-list-item-action",[i("v-icon",[e._v("mdi-pencil")])],1)],1),i("v-list-item",{on:{click:function(i){e.shareDialogStore.show=!0,e.shareDialogStore.data.url=t.url,e.shareDialogStore.data.uuid=t.uuid}}},[i("v-list-item-title",[e._v("Share")]),i("v-list-item-action",[i("v-icon",[e._v("mdi-share")])],1)],1),i("v-list-item",{attrs:{color:"red darken-1"},on:{click:function(i){e.removeDialogStore.show=!0,e.removeDialogStore.uuid=t.uuid}}},[i("v-list-item-title",[e._v("Remove")]),i("v-list-item-action",[i("v-icon",[e._v("mdi-minus")])],1)],1)],1)],1)],1)],1)})),1)},d=[],c=(i("4e827"),i("310e")),u=i.n(c),m={name:"itemiterator",components:{draggable:u.a},props:["itemsForIterator"],data:function(){return{settings:{}}},created:function(){this.settings=this.$store.state.settings},computed:{options:function(){return{name:"column-item",pull:!0,put:!0}},settingsChanged:function(){return this.$store.state.settings},addDialogStore:{get:function(){return this.$store.state.addDialog},set:function(e){this.$store.commit("mutate",{property:"addDialog",with:e})}},editDialogStore:{get:function(){return this.$store.state.editDialog},set:function(e){this.$store.commit("mutate",{property:"editDialog",with:e})}},editFolderDialogStore:{get:function(){return this.$store.state.editFolderDialog},set:function(e){this.$store.commit("mutate",{property:"editFolderDialog",with:e})}},shareDialogStore:{get:function(){return this.$store.state.shareDialog},set:function(e){this.$store.commit("mutate",{property:"shareDialog",with:e})}},removeFolderDialogStore:{get:function(){return this.$store.state.removeFolderDialog},set:function(e){this.$store.commit("mutate",{property:"removeFolderDialog",with:e})}},removeDialogStore:{get:function(){return this.$store.state.removeDialog},set:function(e){this.$store.commit("mutate",{property:"removeDialog",with:e})}}},watch:{settingsChanged:function(e,t){console.info("Settings previous value:",t),e&&(this.settings=e)}},methods:{sendEvent:function(e,t){l.$emit(e,t)},getIcon:function(e){var t;return e=e.toUpperCase(),t=this.$store.state.iconType[e]?this.$store.state.iconType[e].icon:this.$store.state.iconType.UNKNOWN.icon,t},getIconColor:function(e){var t;return e=e.toUpperCase(),t=this.$store.state.iconType[e]?this.$store.state.iconType[e].color:this.$store.state.iconType.UNKNOWN.color,t},sortFolder:function(e,t){var i=this.searchForItem(e);i&&("az"===t&&i.returnedItem.items.sort((function(e,t){var i=e.name.toUpperCase(),r=t.name.toUpperCase();return ir?1:0})),"za"===t&&i.returnedItem.items.sort((function(e,t){var i=e.name.toUpperCase(),r=t.name.toUpperCase();return i>r?-1:i0)return this.recursiveSingularSearch(e,t[i].items)}}}},v=m,g=i("2877"),p=i("6544"),h=i.n(p),f=i("8336"),D=i("a523"),S=i("132d"),y=i("604c"),b=i("8860"),G=i("56b0"),I=i("da13"),F=i("1800"),w=i("5d23"),x=i("e449"),$=Object(g["a"])(v,n,d,!1,null,null,null),_=$.exports;function k(){return"undefined"===typeof EventBridge}h()($,{VBtn:f["a"],VContainer:D["a"],VIcon:S["a"],VItemGroup:y["b"],VList:b["a"],VListGroup:G["a"],VListItem:I["a"],VListItemAction:F["a"],VListItemContent:w["a"],VListItemSubtitle:w["b"],VListItemTitle:w["c"],VMenu:x["a"]}),k()||EventBridge.scriptEventReceived.connect((function(e){if(e=JSON.parse(e),"inventory"===e.app)switch(e.command){case"script-to-web-inventory":r.receiveInventory(e.data);break;case"script-to-web-receiving-item-queue":r.receiveReceivingItemQueue(e.data);break;case"script-to-web-nearby-users":r.receiveNearbyUsers(e.data);break;case"script-to-web-settings":r.receiveSettings(e.data);break}})),l.$on("use-item",(function(e){r.useItem(e.type,e.url)}));var C={name:"App",components:{itemiterator:_},data:function(){return{receivingItemsDialog:{show:!1,data:{receivingItemQueue:[{senderUUID:"SENDERUUIDLOL",senderName:"WHOISTHIS1",senderDistance:2.5,data:{type:"script",name:"This Is A Real Script",url:"https://butwhythough.com/lol.js",uuid:"This Is A Real Script"}},{senderUUID:"TEST2SENDERUUID",senderName:"WHOTHISBE2",senderDistance:1.22,data:{type:"script",name:"REALLYLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG",url:"https://butwhythough.com/looool.js",uuid:"REALLYLONNGGGGGGGG"}}]}},folderList:[],recursiveFolderHoldingList:[],nearbyUsers:[{name:"Who",uuid:"{4131531653652562}",distance:5},{name:"Is",uuid:"{4131531653756756576543652562}",distance:3.23},{name:"This?",uuid:"{4131531676575653652562}",distance:1}],sortBy:"alphabetical",settings:{displayDensity:{size:1,labels:["List","Compact","Large"]}},appVersion:"2.0.2",darkTheme:!0,drawer:!1,disabledProp:!0}},created:function(){r=this,this.$vuetify.theme.dark=this.darkTheme,this.sendAppMessage("ready","")},methods:{createUUID:function(){for(var e=[],t="0123456789abcdef",i=0;i<36;i++)e[i]=t.substr(Math.floor(16*Math.random()),1);e[14]="4",e[19]=t.substr(3&e[19]|8,1),e[8]=e[13]=e[18]=e[23]="-";var r=e.join("");return r},pushToItems:function(e,t,i,r,a){var o;o=null!=a?a:this.createUUID(),this.$store.commit("pushToItems",{type:e,name:t,folder:i,url:r,uuid:o}),null!==i&&"No Folder"!==i&&this.moveItem(o,i)},checkFileType:function(e){var t=null;switch(e){case".fbx":t="MODEL";break;case".gltf":t="MODEL";break;case".glb":t="MODEL";break;case".js":t="SCRIPT";break;case".fst":t="AVATAR";break;case".json":t="JSON";break;default:t="UNKNOWN"}return t},checkItemType:function(e){var t=null;return e=e.toUpperCase(),this.$store.state.supportedItemTypes.forEach((function(i){i===e&&(t=i)})),null===t&&(t="UNKNOWN"),t},createFolder:function(e){this.$store.commit("pushToItems",{name:e,folder:"No Folder",items:[],uuid:this.createUUID()}),this.createFolderDialogStore.data.name=null},editFolder:function(e){var t=this.searchForItem(e);t&&(t.returnedItem.name=this.$store.state.editFolderDialog.data.name,null!==this.$store.state.editFolderDialog.data.folder&&"No Change"!==this.$store.state.editFolderDialog.data.folder&&(t.returnedItem.folder!==this.$store.state.editFolderDialog.data.folder&&"No Folder"!==this.$store.state.editFolderDialog.data.folder?this.moveFolder(e,this.$store.state.editFolderDialog.data.folder):"No Folder"===this.$store.state.editFolderDialog.data.folder&&this.moveFolder(e,"top")))},addItem:function(e,t,i){var r,a=this.detectFileType(i);r=null==a||null==a[0]?"unknown":this.checkFileType(a[0]),this.pushToItems(r,e,t,i,null),this.addDialogStore.data.name=null,this.addDialogStore.data.folder=null,this.addDialogStore.data.url=null},detectFileType:function(e){var t=/\.[0-9a-z]+$/i,i=e.match(t);if(null==i||null==i[0]){var r=/\.[0-9a-z]+$/i,a=new URL(e);i=a.pathname.match(r)}else null!=i&&null!=i[0]||(i=null);return i},removeItem:function(e){var t=this.searchForItem(e);t.parentArray.splice(t.iteration,1)},removeFolder:function(e){var t=this.searchForItem(e);t.parentArray.splice(t.iteration,1)},editItem:function(e){var t,i=this.searchForItem(e);i.returnedItem.type=this.checkItemType(this.$store.state.editDialog.data.type),i.returnedItem.name=this.$store.state.editDialog.data.name,i.returnedItem.folder=this.$store.state.editDialog.data.folder,i.returnedItem.url=this.$store.state.editDialog.data.url;for(var r=0;r0){var a=this.recursiveSingularSearch(e,t[i].items);if(null!==a)return a}}return null},recursiveFolderPopulate:function(e,t){for(var i=0;ir?1:0})),"za"===t.sort&&e.items.sort((function(e,t){var i=e.name.toUpperCase(),r=t.name.toUpperCase();return i>r?-1:i\r\n\r\n\r\n\r\n\r\n\r\n\r\n","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('v-app',[_c('v-app-bar',{attrs:{\"app\":\"\"}},[_c('v-app-bar-nav-icon',{on:{\"click\":function($event){_vm.drawer = true}}}),_c('v-toolbar-title',[_vm._v(\"Inventory\")]),_c('v-spacer'),_c('v-badge',{staticClass:\"mx-5\",attrs:{\"bordered\":\"\",\"color\":\"primary\",\"value\":_vm.receivingItemQueueLength,\"content\":_vm.receivingItemQueueLength,\"overlap\":\"\"}},[_c('v-btn',{attrs:{\"small\":\"\",\"color\":\"red\",\"fab\":\"\"},on:{\"click\":function($event){_vm.receivingItemsDialog.show = true; _vm.sendAppMessage('web-to-script-request-receiving-item-queue', '')}}},[_c('v-icon',[_vm._v(\" mdi-tray-full \")])],1)],1),_c('v-menu',{attrs:{\"bottom\":\"\",\"left\":\"\"},scopedSlots:_vm._u([{key:\"activator\",fn:function(ref){\nvar on = ref.on;\nreturn [_c('v-btn',_vm._g({attrs:{\"large\":\"\",\"color\":\"primary\"}},on),[_c('h4',[_vm._v(\"Sort\")])])]}}])},[_c('v-list',{attrs:{\"color\":\"grey darken-3\"}},[_c('v-list-item',{on:{\"click\":function($event){return _vm.sortTopInventory('az')}}},[_c('v-list-item-title',[_vm._v(\"A-Z\")]),_c('v-list-item-action',[_c('v-icon',{attrs:{\"large\":\"\"}},[_vm._v(\"mdi-sort-alphabetical-ascending\")])],1)],1),_c('v-list-item',{on:{\"click\":function($event){return _vm.sortTopInventory('za')}}},[_c('v-list-item-title',[_vm._v(\"Z-A\")]),_c('v-list-item-action',[_c('v-icon',{attrs:{\"large\":\"\"}},[_vm._v(\"mdi-sort-alphabetical-descending\")])],1)],1)],1)],1)],1),_c('v-navigation-drawer',{attrs:{\"fixed\":\"\",\"temporary\":\"\"},model:{value:(_vm.drawer),callback:function ($$v) {_vm.drawer=$$v},expression:\"drawer\"}},[_c('v-list',{staticClass:\"pt-5\",attrs:{\"nav\":\"\"}},[_c('v-list-item-group',[_c('v-slider',{attrs:{\"tick-labels\":_vm.settings.displayDensity.labels,\"max\":2,\"step\":\"1\",\"ticks\":\"always\",\"tick-size\":\"3\"},model:{value:(_vm.settings.displayDensity.size),callback:function ($$v) {_vm.$set(_vm.settings.displayDensity, \"size\", $$v)},expression:\"settings.displayDensity.size\"}}),_c('v-list-item',{on:{\"click\":function($event){_vm.addDialogStore.show = true; _vm.getFolderList('add');}}},[_c('v-list-item-icon',[_c('v-icon',[_vm._v(\"mdi-plus\")])],1),_c('v-list-item-title',[_vm._v(\"Add Item\")])],1),_c('v-list-item',{on:{\"click\":function($event){_vm.createFolderDialogStore.show = true}}},[_c('v-list-item-icon',[_c('v-icon',[_vm._v(\"mdi-folder-plus\")])],1),_c('v-list-item-title',[_vm._v(\"Create Folder\")])],1),_c('p',{staticClass:\"app-version\"},[_vm._v(\"Version \"+_vm._s(_vm.appVersion))])],1)],1)],1),_c('v-content',[_c('v-container',{attrs:{\"fluid\":\"\"}},[_c('v-col',{staticClass:\"py-1 column-item\",attrs:{\"cols\":\"12\",\"sm\":\"6\",\"md\":\"4\",\"lg\":\"3\"}},[_c('itemiterator',{attrs:{\"itemsForIterator\":this.$store.state.items}})],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\"},model:{value:(_vm.receivingItemsDialog.show),callback:function ($$v) {_vm.$set(_vm.receivingItemsDialog, \"show\", $$v)},expression:\"receivingItemsDialog.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Item Inbox\")]),_c('v-card-text',{directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.receivingItemQueueLength > 0),expression:\"receivingItemQueueLength > 0\"}]},[_vm._v(\" A list of all items being received currently. \")]),_c('v-card-text',{directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.receivingItemQueueLength === 0),expression:\"receivingItemQueueLength === 0\"}]},[_vm._v(\" There are currently no items in your inbox. \")]),_c('v-card-actions',[_c('v-list',{directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.receivingItemQueueLength > 0),expression:\"receivingItemQueueLength > 0\"}],staticClass:\"pt-5\",attrs:{\"nav\":\"\",\"max-width\":\"370\"}},_vm._l((_vm.receivingItemsDialog.data.receivingItemQueue),function(item){return _c('v-list-item',{key:item.data.uuid,attrs:{\"two-line\":\"\"}},[_c('v-list-item-content',[_c('v-list-item-title',[_vm._v(_vm._s(item.data.name))]),_c('v-list-item-subtitle',[_vm._v(\"Sent by \"+_vm._s(item.senderName))]),_c('v-list-item-subtitle',[_vm._v(\"Distance: \"+_vm._s(item.senderDistance.toFixed(1))+\"m\")])],1),_c('v-btn',{attrs:{\"color\":\"success\"},on:{\"click\":function($event){return _vm.acceptReceivingItem(item)}}},[_c('v-icon',[_vm._v(\"mdi-plus\")])],1),_c('v-btn',{attrs:{\"text\":\"\",\"color\":\"red\"},on:{\"click\":function($event){return _vm.removeReceivingItem(item.data.uuid)}}},[_c('v-icon',[_vm._v(\"mdi-minus\")])],1)],1)}),1)],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"290\"},model:{value:(_vm.removeDialogStore.show),callback:function ($$v) {_vm.$set(_vm.removeDialogStore, \"show\", $$v)},expression:\"removeDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Remove Item\")]),_c('v-card-text',[_vm._v(\" Are you sure you want to delete this item from your inventory? \")]),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\"},on:{\"click\":function($event){_vm.removeDialogStore.show = false}}},[_vm._v(\" No \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.removeDialogStore.show = false; _vm.removeItem(_vm.$store.state.removeDialog.uuid);}}},[_vm._v(\" Yes \")])],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"290\"},model:{value:(_vm.removeFolderDialogStore.show),callback:function ($$v) {_vm.$set(_vm.removeFolderDialogStore, \"show\", $$v)},expression:\"removeFolderDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Remove Folder\")]),_c('v-card-text',[_vm._v(\" Are you sure you want to delete this folder \"),_c('b',[_vm._v(\"and\")]),_vm._v(\" all items within from your inventory? \")]),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\"},on:{\"click\":function($event){_vm.removeFolderDialogStore.show = false}}},[_vm._v(\" No \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.removeFolderDialogStore.show = false; _vm.removeFolder(_vm.$store.state.removeFolderDialog.uuid);}}},[_vm._v(\" Yes \")])],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\"},model:{value:(_vm.editDialogStore.show),callback:function ($$v) {_vm.$set(_vm.editDialogStore, \"show\", $$v)},expression:\"editDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Edit Item\")]),_c('v-form',{ref:\"editForm\",attrs:{\"lazy-validation\":false},model:{value:(_vm.editDialogStore.valid),callback:function ($$v) {_vm.$set(_vm.editDialogStore, \"valid\", $$v)},expression:\"editDialogStore.valid\"}},[_c('v-select',{staticClass:\"my-2\",attrs:{\"items\":_vm.$store.state.supportedItemTypes,\"rules\":[function (v) { return !!v || 'Type is required.'; }],\"label\":\"Item Type\",\"outlined\":\"\"},model:{value:(_vm.editDialogStore.data.type),callback:function ($$v) {_vm.$set(_vm.editDialogStore.data, \"type\", $$v)},expression:\"editDialogStore.data.type\"}}),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"Name\",\"rules\":[function (v) { return !!v || 'Name is required.'; }],\"required\":\"\"},model:{value:(_vm.editDialogStore.data.name),callback:function ($$v) {_vm.$set(_vm.editDialogStore.data, \"name\", $$v)},expression:\"editDialogStore.data.name\"}}),_c('v-select',{staticClass:\"my-2\",attrs:{\"items\":_vm.folderList,\"item-text\":\"name\",\"item-value\":\"uuid\",\"label\":\"Folder\",\"outlined\":\"\"},model:{value:(_vm.editDialogStore.data.folder),callback:function ($$v) {_vm.$set(_vm.editDialogStore.data, \"folder\", $$v)},expression:\"editDialogStore.data.folder\"}}),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"URL\",\"rules\":[function (v) { return !!v || 'URL is required.'; }],\"required\":\"\"},model:{value:(_vm.editDialogStore.data.url),callback:function ($$v) {_vm.$set(_vm.editDialogStore.data, \"url\", $$v)},expression:\"editDialogStore.data.url\"}}),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.editDialogStore.show = false}}},[_vm._v(\" Cancel \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\",\"disabled\":!_vm.$store.state.editDialog.valid},on:{\"click\":function($event){_vm.editDialogStore.show = false; _vm.editItem(_vm.$store.state.editDialog.uuid);}}},[_vm._v(\" Done \")])],1)],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\"},model:{value:(_vm.editFolderDialogStore.show),callback:function ($$v) {_vm.$set(_vm.editFolderDialogStore, \"show\", $$v)},expression:\"editFolderDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Edit Folder\")]),_c('v-form',{ref:\"editFolderForm\",attrs:{\"lazy-validation\":false},model:{value:(_vm.editFolderDialogStore.valid),callback:function ($$v) {_vm.$set(_vm.editFolderDialogStore, \"valid\", $$v)},expression:\"editFolderDialogStore.valid\"}},[_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"Name\",\"rules\":[function (v) { return !!v || 'Name is required.'; }],\"required\":\"\"},model:{value:(_vm.editFolderDialogStore.data.name),callback:function ($$v) {_vm.$set(_vm.editFolderDialogStore.data, \"name\", $$v)},expression:\"editFolderDialogStore.data.name\"}}),_c('v-select',{staticClass:\"my-2\",attrs:{\"items\":_vm.folderList,\"item-text\":\"name\",\"item-value\":\"uuid\",\"label\":\"Parent Folder\",\"outlined\":\"\"},model:{value:(_vm.editFolderDialogStore.data.folder),callback:function ($$v) {_vm.$set(_vm.editFolderDialogStore.data, \"folder\", $$v)},expression:\"editFolderDialogStore.data.folder\"}}),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.editFolderDialogStore.show = false}}},[_vm._v(\" Cancel \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\",\"disabled\":!_vm.$store.state.editFolderDialog.valid},on:{\"click\":function($event){_vm.editFolderDialogStore.show = false; _vm.editFolder(_vm.$store.state.editFolderDialog.data.uuid);}}},[_vm._v(\" Done \")])],1)],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\"},model:{value:(_vm.createFolderDialogStore.show),callback:function ($$v) {_vm.$set(_vm.createFolderDialogStore, \"show\", $$v)},expression:\"createFolderDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Create Folder\")]),_c('v-card-text',[_vm._v(\" Enter the name of the folder. \")]),_c('v-form',{ref:\"createFolderForm\",attrs:{\"lazy-validation\":false},model:{value:(_vm.createFolderDialogStore.valid),callback:function ($$v) {_vm.$set(_vm.createFolderDialogStore, \"valid\", $$v)},expression:\"createFolderDialogStore.valid\"}},[_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"Name\",\"rules\":[function (v) { return !!v || 'Name is required.'; }],\"required\":\"\"},model:{value:(_vm.createFolderDialogStore.data.name),callback:function ($$v) {_vm.$set(_vm.createFolderDialogStore.data, \"name\", $$v)},expression:\"createFolderDialogStore.data.name\"}}),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.createFolderDialogStore.show = false}}},[_vm._v(\" Cancel \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\",\"disabled\":!_vm.$store.state.createFolderDialog.valid},on:{\"click\":function($event){_vm.createFolderDialogStore.show = false; _vm.createFolder(_vm.$store.state.createFolderDialog.data.name)}}},[_vm._v(\" Create \")])],1)],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\"},model:{value:(_vm.addDialogStore.show),callback:function ($$v) {_vm.$set(_vm.addDialogStore, \"show\", $$v)},expression:\"addDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Add Item\")]),_c('v-form',{ref:\"addForm\",attrs:{\"lazy-validation\":false},model:{value:(_vm.addDialogStore.valid),callback:function ($$v) {_vm.$set(_vm.addDialogStore, \"valid\", $$v)},expression:\"addDialogStore.valid\"}},[_c('v-card-text',[_vm._v(\" Enter the name of the item. \")]),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"Name\",\"rules\":[function (v) { return !!v || 'Name is required.'; }],\"required\":\"\"},model:{value:(_vm.addDialogStore.data.name),callback:function ($$v) {_vm.$set(_vm.addDialogStore.data, \"name\", $$v)},expression:\"addDialogStore.data.name\"}}),_c('v-card-text',[_vm._v(\" Select a folder (optional). \")]),_c('v-select',{staticClass:\"my-2\",attrs:{\"items\":_vm.folderList,\"label\":\"Folder\",\"outlined\":\"\",\"item-text\":\"name\",\"item-value\":\"uuid\"},model:{value:(_vm.addDialogStore.data.folder),callback:function ($$v) {_vm.$set(_vm.addDialogStore.data, \"folder\", $$v)},expression:\"addDialogStore.data.folder\"}}),_c('v-card-text',[_vm._v(\" Enter the URL of the item. \")]),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"URL\",\"rules\":[function (v) { return !!v || 'URL is required.'; }],\"required\":\"\"},model:{value:(_vm.addDialogStore.data.url),callback:function ($$v) {_vm.$set(_vm.addDialogStore.data, \"url\", $$v)},expression:\"addDialogStore.data.url\"}}),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.addDialogStore.show = false}}},[_vm._v(\" Cancel \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\",\"disabled\":!_vm.$store.state.addDialog.valid},on:{\"click\":function($event){_vm.addDialogStore.show = false; _vm.addItem(_vm.$store.state.addDialog.data.name, _vm.$store.state.addDialog.data.folder, _vm.$store.state.addDialog.data.url)}}},[_vm._v(\" Add \")])],1)],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\",\"persistent\":\"\"},model:{value:(_vm.receiveDialogStore.show),callback:function ($$v) {_vm.$set(_vm.receiveDialogStore, \"show\", $$v)},expression:\"receiveDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Receiving Item\")]),_c('v-card-text',[_c('b',[_vm._v(_vm._s(_vm.$store.state.receiveDialog.data.userDisplayName)+\" sent you an item.\")]),_vm._v(\" \"),_c('br'),_c('i',{staticClass:\"caption\"},[_vm._v(\"User UUID: \"+_vm._s(_vm.$store.state.receiveDialog.data.userUUID))])]),_c('v-form',{ref:\"receiveForm\",attrs:{\"lazy-validation\":false},model:{value:(_vm.receiveDialogStore.valid),callback:function ($$v) {_vm.$set(_vm.receiveDialogStore, \"valid\", $$v)},expression:\"receiveDialogStore.valid\"}},[_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"Type\",\"rules\":[function (v) { return !!v || 'Type is required.'; }],\"required\":\"\"},model:{value:(_vm.receiveDialogStore.data.type),callback:function ($$v) {_vm.$set(_vm.receiveDialogStore.data, \"type\", $$v)},expression:\"receiveDialogStore.data.type\"}}),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"Name\",\"rules\":[function (v) { return !!v || 'Name is required.'; }],\"required\":\"\"},model:{value:(_vm.receiveDialogStore.data.name),callback:function ($$v) {_vm.$set(_vm.receiveDialogStore.data, \"name\", $$v)},expression:\"receiveDialogStore.data.name\"}}),_c('v-card-text',[_vm._v(\" Select a folder (optional). \")]),_c('v-select',{staticClass:\"my-2\",attrs:{\"items\":_vm.folderList,\"label\":\"Folder\",\"outlined\":\"\",\"item-text\":\"name\",\"item-value\":\"uuid\"},model:{value:(_vm.receiveDialogStore.data.folder),callback:function ($$v) {_vm.$set(_vm.receiveDialogStore.data, \"folder\", $$v)},expression:\"receiveDialogStore.data.folder\"}}),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"URL\",\"rules\":[function (v) { return !!v || 'URL is required.'; }],\"required\":\"\"},model:{value:(_vm.receiveDialogStore.data.url),callback:function ($$v) {_vm.$set(_vm.receiveDialogStore.data, \"url\", $$v)},expression:\"receiveDialogStore.data.url\"}}),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.receiveDialogStore.show = false}}},[_vm._v(\" Reject \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\",\"disabled\":!_vm.$store.state.receiveDialog.valid},on:{\"click\":function($event){_vm.receiveDialogStore.show = false; _vm.confirmItemReceipt();}}},[_vm._v(\" Accept \")])],1)],1)],1)],1),_c('v-dialog',{attrs:{\"max-width\":\"380\",\"persistent\":\"\"},model:{value:(_vm.shareDialogStore.show),callback:function ($$v) {_vm.$set(_vm.shareDialogStore, \"show\", $$v)},expression:\"shareDialogStore.show\"}},[_c('v-card',[_c('v-card-title',{staticClass:\"headline\"},[_vm._v(\"Share Item\")]),_c('v-card-text',[_vm._v(\" Select a user to send this item to. \")]),_c('v-form',{ref:\"shareForm\",staticClass:\"px-2\",attrs:{\"lazy-validation\":false},model:{value:(_vm.shareDialogStore.valid),callback:function ($$v) {_vm.$set(_vm.shareDialogStore, \"valid\", $$v)},expression:\"shareDialogStore.valid\"}},[_c('v-select',{attrs:{\"items\":_vm.nearbyUsers,\"item-value\":\"uuid\",\"rules\":[function (v) { return !!v || 'A recipient is required'; }],\"label\":\"Nearby Users\",\"required\":\"\"},scopedSlots:_vm._u([{key:\"item\",fn:function(data){return [_c('i',{staticStyle:{\"color\":\"grey\",\"margin-right\":\"5px\"}},[_vm._v(_vm._s(data.item.distance.toFixed(1))+\"m\")]),_vm._v(\" \"+_vm._s(data.item.name)+\" \")]}},{key:\"selection\",fn:function(data){return [_c('i',{staticStyle:{\"color\":\"grey\",\"margin-right\":\"5px\"}},[_vm._v(_vm._s(data.item.distance.toFixed(1))+\"m\")]),_vm._v(\" \"+_vm._s(data.item.name)+\" \")]}}]),model:{value:(_vm.shareDialogStore.data.recipient),callback:function ($$v) {_vm.$set(_vm.shareDialogStore.data, \"recipient\", $$v)},expression:\"shareDialogStore.data.recipient\"}}),_c('v-text-field',{staticClass:\"px-2\",attrs:{\"label\":\"URL\",\"rules\":[function (v) { return !!v || 'URL is required.'; }],\"required\":\"\"},model:{value:(_vm.shareDialogStore.data.url),callback:function ($$v) {_vm.$set(_vm.shareDialogStore.data, \"url\", $$v)},expression:\"shareDialogStore.data.url\"}}),_c('v-card-actions',[_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"red\"},on:{\"click\":function($event){_vm.shareDialogStore.show = false}}},[_vm._v(\" Cancel \")]),_c('v-spacer'),_c('v-btn',{staticClass:\"px-3\",attrs:{\"color\":\"blue\",\"disabled\":!_vm.$store.state.shareDialog.valid},on:{\"click\":function($event){_vm.shareDialogStore.show = false; _vm.shareItem(_vm.$store.state.shareDialog.data.uuid);}}},[_vm._v(\" Send \")])],1)],1)],1)],1)],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","/*\r\n event-bus.js\r\n\r\n Created by Kalila L. on 21 May 2020.\r\n Copyright 2020 Vircadia and contributors.\r\n \r\n Distributed under the Apache License, Version 2.0.\r\n See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html\r\n*/\r\n\r\nimport Vue from 'vue';\r\nexport const EventBus = new Vue();","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('draggable',{attrs:{\"group\":_vm.options,\"list\":_vm.itemsForIterator,\"handle\":\".handle\"}},_vm._l((_vm.itemsForIterator),function(item){return _c('v-item-group',{key:item.uuid},[(!item.items)?_c('v-list-item',{staticClass:\"mx-auto draggable-card\",attrs:{\"one-line\":\"\",\"max-width\":\"344\",\"outlined\":\"\"}},[_c('div',{staticClass:\"handle pa-2\"},[_c('v-icon',{attrs:{\"color\":\"orange darken-2\"}},[_vm._v(\"mdi-square-medium-outline\")])],1),_c('v-list-item-content',{staticClass:\"pb-1 pt-2 pl-4\"},[_c('div',{directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.settings.displayDensity.size > 0),expression:\"settings.displayDensity.size > 0\"}],staticClass:\"overline\",staticStyle:{\"font-size\":\"0.825rem !important\"}},[_vm._v(_vm._s(item.type))]),_c('v-list-item-title',{staticClass:\"subtitle-1 mb-1\"},[_vm._v(_vm._s(item.name))]),_c('v-list-item-subtitle',{directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.settings.displayDensity.size == 2),expression:\"settings.displayDensity.size == 2\"}]},[_vm._v(_vm._s(item.url))])],1),_c('v-menu',{attrs:{\"bottom\":\"\",\"left\":\"\"},scopedSlots:_vm._u([{key:\"activator\",fn:function(ref){\nvar on = ref.on;\nreturn [_c('v-btn',_vm._g({directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.settings.displayDensity.size >= 1),expression:\"settings.displayDensity.size >= 1\"}],style:({backgroundColor: (_vm.getIconColor(item.type)) }),attrs:{\"medium\":\"\",\"fab\":\"\",\"dark\":\"\"}},on),[_c('v-icon',[_vm._v(_vm._s(_vm.getIcon(item.type)))])],1),_c('v-btn',_vm._g({directives:[{name:\"show\",rawName:\"v-show\",value:(_vm.settings.displayDensity.size < 1),expression:\"settings.displayDensity.size < 1\"}],style:({backgroundColor: (_vm.getIconColor(item.type)) }),attrs:{\"small\":\"\",\"fab\":\"\",\"dark\":\"\"}},on),[_c('v-icon',[_vm._v(_vm._s(_vm.getIcon(item.type)))])],1)]}}],null,true)},[_c('v-list',{attrs:{\"color\":\"grey darken-3\"}},[_c('v-list-item',{on:{\"click\":function($event){return _vm.sendEvent('use-item', { 'type': item.type, 'url': item.url })}}},[_c('v-list-item-title',[_vm._v(\"Use\")]),_c('v-list-item-action',[_c('v-icon',[_vm._v(\"mdi-play\")])],1)],1),_c('v-list-item',{on:{\"click\":function($event){_vm.editDialogStore.show = true; \n _vm.editDialogStore.uuid = item.uuid;\n _vm.editDialogStore.data.type = item.type.toUpperCase();\n _vm.editDialogStore.data.folder = null;\n _vm.editDialogStore.data.name = item.name;\n _vm.editDialogStore.data.url = item.url;}}},[_c('v-list-item-title',[_vm._v(\"Edit\")]),_c('v-list-item-action',[_c('v-icon',[_vm._v(\"mdi-pencil\")])],1)],1),_c('v-list-item',{on:{\"click\":function($event){_vm.shareDialogStore.show = true; \n _vm.shareDialogStore.data.url = item.url; \n _vm.shareDialogStore.data.uuid = item.uuid;}}},[_c('v-list-item-title',[_vm._v(\"Share\")]),_c('v-list-item-action',[_c('v-icon',[_vm._v(\"mdi-share\")])],1)],1),_c('v-list-item',{attrs:{\"color\":\"red darken-1\"},on:{\"click\":function($event){_vm.removeDialogStore.show = true; \n _vm.removeDialogStore.uuid = item.uuid;}}},[_c('v-list-item-title',[_vm._v(\"Remove\")]),_c('v-list-item-action',[_c('v-icon',[_vm._v(\"mdi-minus\")])],1)],1)],1)],1)],1):_c('v-list-group',{staticClass:\"top-level-folder\",scopedSlots:_vm._u([{key:\"activator\",fn:function(){return [_c('v-list-item',{staticClass:\"mx-auto\",attrs:{\"one-line\":\"\",\"max-width\":\"344\",\"outlined\":\"\"}},[_c('v-icon',{staticClass:\"folder-icon\",attrs:{\"color\":\"teal\"}},[_vm._v(\"mdi-folder-settings\")]),_vm._v(\" \"+_vm._s(item.name)+\" \")],1)]},proxy:true}],null,true)},[_c('div',{staticClass:\"text-center my-2\"},[_c('v-btn',{staticClass:\"mx-1 folder-button\",attrs:{\"medium\":\"\",\"tile\":\"\",\"color\":\"purple\"},on:{\"click\":function($event){_vm.editFolderDialogStore.data.uuid = item.uuid;\n _vm.editFolderDialogStore.data.name = item.name;\n _vm.editFolderDialogStore.show = true;}}},[_c('v-icon',[_vm._v(\"mdi-pencil\")])],1),_c('v-btn',{staticClass:\"mx-1 folder-button\",attrs:{\"medium\":\"\",\"tile\":\"\",\"color\":\"red\"},on:{\"click\":function($event){_vm.removeFolderDialogStore.show = true; \n _vm.removeFolderDialogStore.uuid = item.uuid;}}},[_c('v-icon',[_vm._v(\"mdi-minus\")])],1),_c('v-menu',{attrs:{\"bottom\":\"\",\"left\":\"\"},scopedSlots:_vm._u([{key:\"activator\",fn:function(ref){\n var on = ref.on;\nreturn [_c('v-btn',_vm._g({staticClass:\"mx-1 folder-button\",attrs:{\"medium\":\"\",\"tile\":\"\",\"color\":\"blue\"}},on),[_c('v-icon',[_vm._v(\"mdi-sort\")])],1)]}}],null,true)},[_c('v-list',{attrs:{\"color\":\"grey darken-3\"}},[_c('v-list-item',{on:{\"click\":function($event){return _vm.sortFolder(item.uuid, 'az');}}},[_c('v-list-item-title',[_vm._v(\"A-Z\")]),_c('v-list-item-action',[_c('v-icon',{attrs:{\"large\":\"\"}},[_vm._v(\"mdi-sort-alphabetical-ascending\")])],1)],1),_c('v-list-item',{on:{\"click\":function($event){return _vm.sortFolder(item.uuid, 'za');}}},[_c('v-list-item-title',[_vm._v(\"Z-A\")]),_c('v-list-item-action',[_c('v-icon',{attrs:{\"large\":\"\"}},[_vm._v(\"mdi-sort-alphabetical-descending\")])],1)],1)],1)],1)],1),_c('v-container',{attrs:{\"fluid\":\"\"}},[_c('itemiterator',{key:item.uuid,attrs:{\"itemsForIterator\":item.items}})],1)],1)],1)}),1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\r\n\r\n\r\n\r\n\r\n\r\n","import mod from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./ItemIterator.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/cache-loader/dist/cjs.js??ref--12-0!../../node_modules/thread-loader/dist/cjs.js!../../node_modules/babel-loader/lib/index.js!../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./ItemIterator.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./ItemIterator.vue?vue&type=template&id=366e0b2f&\"\nimport script from \"./ItemIterator.vue?vue&type=script&lang=js&\"\nexport * from \"./ItemIterator.vue?vue&type=script&lang=js&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports\n\n/* vuetify-loader */\nimport installComponents from \"!../../node_modules/vuetify-loader/lib/runtime/installComponents.js\"\nimport { VBtn } from 'vuetify/lib/components/VBtn';\nimport { VContainer } from 'vuetify/lib/components/VGrid';\nimport { VIcon } from 'vuetify/lib/components/VIcon';\nimport { VItemGroup } from 'vuetify/lib/components/VItemGroup';\nimport { VList } from 'vuetify/lib/components/VList';\nimport { VListGroup } from 'vuetify/lib/components/VList';\nimport { VListItem } from 'vuetify/lib/components/VList';\nimport { VListItemAction } from 'vuetify/lib/components/VList';\nimport { VListItemContent } from 'vuetify/lib/components/VList';\nimport { VListItemSubtitle } from 'vuetify/lib/components/VList';\nimport { VListItemTitle } from 'vuetify/lib/components/VList';\nimport { VMenu } from 'vuetify/lib/components/VMenu';\ninstallComponents(component, {VBtn,VContainer,VIcon,VItemGroup,VList,VListGroup,VListItem,VListItemAction,VListItemContent,VListItemSubtitle,VListItemTitle,VMenu})\n","import mod from \"-!../node_modules/cache-loader/dist/cjs.js??ref--12-0!../node_modules/thread-loader/dist/cjs.js!../node_modules/babel-loader/lib/index.js!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../node_modules/cache-loader/dist/cjs.js??ref--12-0!../node_modules/thread-loader/dist/cjs.js!../node_modules/babel-loader/lib/index.js!../node_modules/cache-loader/dist/cjs.js??ref--0-0!../node_modules/vue-loader/lib/index.js??vue-loader-options!./App.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./App.vue?vue&type=template&id=07483036&\"\nimport script from \"./App.vue?vue&type=script&lang=js&\"\nexport * from \"./App.vue?vue&type=script&lang=js&\"\nimport style0 from \"./App.vue?vue&type=style&index=0&lang=css&\"\n\n\n/* normalize component */\nimport normalizer from \"!../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports\n\n/* vuetify-loader */\nimport installComponents from \"!../node_modules/vuetify-loader/lib/runtime/installComponents.js\"\nimport { VApp } from 'vuetify/lib/components/VApp';\nimport { VAppBar } from 'vuetify/lib/components/VAppBar';\nimport { VAppBarNavIcon } from 'vuetify/lib/components/VAppBar';\nimport { VBadge } from 'vuetify/lib/components/VBadge';\nimport { VBtn } from 'vuetify/lib/components/VBtn';\nimport { VCard } from 'vuetify/lib/components/VCard';\nimport { VCardActions } from 'vuetify/lib/components/VCard';\nimport { VCardText } from 'vuetify/lib/components/VCard';\nimport { VCardTitle } from 'vuetify/lib/components/VCard';\nimport { VCol } from 'vuetify/lib/components/VGrid';\nimport { VContainer } from 'vuetify/lib/components/VGrid';\nimport { VContent } from 'vuetify/lib/components/VContent';\nimport { VDialog } from 'vuetify/lib/components/VDialog';\nimport { VForm } from 'vuetify/lib/components/VForm';\nimport { VIcon } from 'vuetify/lib/components/VIcon';\nimport { VList } from 'vuetify/lib/components/VList';\nimport { VListItem } from 'vuetify/lib/components/VList';\nimport { VListItemAction } from 'vuetify/lib/components/VList';\nimport { VListItemContent } from 'vuetify/lib/components/VList';\nimport { VListItemGroup } from 'vuetify/lib/components/VList';\nimport { VListItemIcon } from 'vuetify/lib/components/VList';\nimport { VListItemSubtitle } from 'vuetify/lib/components/VList';\nimport { VListItemTitle } from 'vuetify/lib/components/VList';\nimport { VMenu } from 'vuetify/lib/components/VMenu';\nimport { VNavigationDrawer } from 'vuetify/lib/components/VNavigationDrawer';\nimport { VSelect } from 'vuetify/lib/components/VSelect';\nimport { VSlider } from 'vuetify/lib/components/VSlider';\nimport { VSpacer } from 'vuetify/lib/components/VGrid';\nimport { VTextField } from 'vuetify/lib/components/VTextField';\nimport { VToolbarTitle } from 'vuetify/lib/components/VToolbar';\ninstallComponents(component, {VApp,VAppBar,VAppBarNavIcon,VBadge,VBtn,VCard,VCardActions,VCardText,VCardTitle,VCol,VContainer,VContent,VDialog,VForm,VIcon,VList,VListItem,VListItemAction,VListItemContent,VListItemGroup,VListItemIcon,VListItemSubtitle,VListItemTitle,VMenu,VNavigationDrawer,VSelect,VSlider,VSpacer,VTextField,VToolbarTitle})\n","/*\r\n vuetify.js\r\n\r\n Created by Kalila L. on 7 Apr 2020\r\n Copyright 2020 Vircadia and contributors.\r\n \r\n Distributed under the Apache License, Version 2.0.\r\n See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html\r\n*/\r\n\r\nimport Vue from 'vue';\r\nimport Vuetify from 'vuetify/lib';\r\n\r\nVue.use(Vuetify);\r\n\r\nexport default new Vuetify({\r\n});\r\n","/*\r\n store.js\r\n\r\n Created by Kalila L. on 16 Apr 2020.\r\n Copyright 2020 Vircadia and contributors.\r\n \r\n Distributed under the Apache License, Version 2.0.\r\n See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html\r\n*/\r\n\r\nimport Vue from 'vue';\r\nimport Vuex from 'vuex';\r\n\r\nVue.use(Vuex);\r\n\r\nexport const store = new Vuex.Store({\r\n devtools: true,\r\n state: {\r\n items: [\r\n // This is test data and is primarily used for in browser development.\r\n {\r\n \"type\": \"script\",\r\n \"name\": \"VRGrabScale\",\r\n \"url\": \"https://gooawefaweawfgle.com/vr.js\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"54254354353\"\r\n },\r\n {\r\n \"name\": \"Test Folder\",\r\n \"folder\": \"No Folder\",\r\n \"items\": [\r\n {\r\n \"name\": \"inception1\",\r\n \"folder\": \"Test Folder\",\r\n \"items\": [\r\n {\r\n \"name\": \"inception2\",\r\n \"folder\": \"Test Folder\",\r\n \"items\": [\r\n {\r\n \"type\": \"script\",\r\n \"name\": \"itemincepted\",\r\n \"url\": \"https://googfdafsgaergale.com/vr.js\",\r\n \"folder\": \"FolderWithinAFolder\",\r\n \"uuid\": \"hkjkjhkjk\",\r\n },\r\n ],\r\n \"uuid\": \"adsfa32\"\r\n },\r\n ],\r\n \"uuid\": \"s4g4sg\"\r\n },\r\n ],\r\n \"uuid\": \"sdfsdf\",\r\n },\r\n {\r\n \"type\": \"script\",\r\n \"name\": \"VRGrabScale\",\r\n \"url\": \"https://googfdafsgaergale.com/vr.js\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"54hgfhgf254354353\",\r\n },\r\n {\r\n \"type\": \"script\",\r\n \"name\": \"TEST\",\r\n \"url\": \"https://gooadfdagle.com/vr.js\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"542rfwat4t5fsddf4354353\",\r\n },\r\n {\r\n \"type\": \"json\",\r\n \"name\": \"TESTJSON\",\r\n \"url\": \"https://gooadfdagle.com/vr.json\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"542rfwat4t54354353\",\r\n },\r\n {\r\n \"type\": \"script\",\r\n \"name\": \"TESTLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG\",\r\n \"url\": \"https://googfdaffle.com/vrLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.js\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"5425ggsrg45354353\",\r\n },\r\n {\r\n \"type\": \"whatttype\",\r\n \"name\": \"BrokenIcon\",\r\n \"url\": \"https://googfdaffle.com/vrLONGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.js\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"5425ggsrg4fdaffdff535asdasd4353\",\r\n },\r\n {\r\n \"type\": \"avatar\",\r\n \"name\": \"AVI\",\r\n \"url\": \"https://googlfadfe.com/vr.fst\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"542gregg45s3g4354353\",\r\n },\r\n {\r\n \"type\": \"avatar\",\r\n \"name\": \"AVI\",\r\n \"url\": \"https://googlefdaf.com/vr.fst\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"5420798-087-54354353\",\r\n },\r\n {\r\n \"type\": \"model\",\r\n \"name\": \"3D MODEL\",\r\n \"url\": \"https://googlee.com/vr.fbx\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"54254354980-7667jt353\",\r\n },\r\n {\r\n \"type\": \"place\",\r\n \"name\": \"PLACE DOMAIN\",\r\n \"url\": \"https://googleee.com/vr.fbx\",\r\n \"folder\": \"No Folder\",\r\n \"uuid\": \"542543sg45s4gg54353\",\r\n },\r\n ],\r\n settings: {\r\n \"displayDensity\": {\r\n \"size\": 1,\r\n \"labels\": [\r\n \"List\",\r\n \"Compact\",\r\n \"Large\",\r\n ],\r\n },\r\n },\r\n iconType: {\r\n \"SCRIPT\": {\r\n \"icon\": \"mdi-code-tags\",\r\n \"color\": \"red\",\r\n },\r\n \"MODEL\": {\r\n \"icon\": \"mdi-video-3d\",\r\n \"color\": \"green\",\r\n },\r\n \"AVATAR\": {\r\n \"icon\": \"mdi-account-convert\",\r\n \"color\": \"purple\",\r\n },\r\n \"PLACE\": {\r\n \"icon\": \"mdi-earth\",\r\n \"color\": \"#0097A7\", // cyan darken-2\r\n },\r\n \"JSON\": {\r\n \"icon\": \"mdi-inbox-multiple\",\r\n \"color\": \"#37474F\", // blue-grey darken-3\r\n },\r\n \"UNKNOWN\": {\r\n \"icon\": \"mdi-help\",\r\n \"color\": \"grey\",\r\n }\r\n },\r\n supportedItemTypes: [\r\n \"SCRIPT\",\r\n \"MODEL\",\r\n \"AVATAR\",\r\n \"PLACE\",\r\n \"JSON\",\r\n \"UNKNOWN\",\r\n ],\r\n removeDialog: {\r\n show: false,\r\n uuid: null,\r\n },\r\n removeFolderDialog: {\r\n show: false,\r\n uuid: null,\r\n },\r\n createFolderDialog: {\r\n show: false,\r\n valid: false,\r\n data: {\r\n \"name\": null,\r\n },\r\n },\r\n addDialog: {\r\n show: false,\r\n valid: false,\r\n data: {\r\n \"name\": null,\r\n \"folder\": null,\r\n \"url\": null,\r\n },\r\n },\r\n editDialog: {\r\n show: false,\r\n valid: false,\r\n uuid: null, //\r\n data: {\r\n \"type\": null,\r\n \"name\": null,\r\n \"url\": null,\r\n \"folder\": null,\r\n },\r\n },\r\n editFolderDialog: {\r\n show: false,\r\n valid: false,\r\n uuid: null, //\r\n data: {\r\n \"name\": null,\r\n \"folder\": null,\r\n },\r\n },\r\n receiveDialog: {\r\n show: false,\r\n valid: false,\r\n data: {\r\n \"userUUID\": null,\r\n \"userDisplayName\": null,\r\n \"name\": null,\r\n \"folder\": null,\r\n \"type\": null,\r\n \"url\": null,\r\n },\r\n },\r\n shareDialog: {\r\n show: false,\r\n valid: false,\r\n data: {\r\n \"uuid\": null, // UUID of the item you want to share. THIS IS THE KEY.\r\n \"url\": null, // The item you want to share.\r\n \"recipient\": null,\r\n }\r\n },\r\n },\r\n mutations: {\r\n mutate (state, payload) {\r\n state[payload.property] = payload.with;\r\n // console.info(\"Payload:\", payload.property, \"with:\", payload.with, \"state is now:\", this.state);\r\n },\r\n sortTopInventory (state, payload) {\r\n let { items } = state;\r\n \r\n if (payload.sort === \"az\") {\r\n state.items.sort(function(a, b) {\r\n var nameA = a.name.toUpperCase(); // ignore upper and lowercase\r\n var nameB = b.name.toUpperCase(); // ignore upper and lowercase\r\n if (nameA < nameB) {\r\n return -1;\r\n }\r\n if (nameA > nameB) {\r\n return 1;\r\n }\r\n \r\n // names must be equal\r\n return 0;\r\n });\r\n } \r\n \r\n if (payload.sort === \"za\") {\r\n state.items.sort(function(a, b) {\r\n var nameA = a.name.toUpperCase(); // ignore upper and lowercase\r\n var nameB = b.name.toUpperCase(); // ignore upper and lowercase\r\n if (nameA > nameB) {\r\n return -1;\r\n }\r\n if (nameA < nameB) {\r\n return 1;\r\n }\r\n \r\n // names must be equal\r\n return 0;\r\n });\r\n }\r\n \r\n Vue.set(state,'items', items);\r\n },\r\n pushToItems (state, payload) {\r\n let { items } = state;\r\n items.push(payload);\r\n \r\n Vue.set(state,'items', items);\r\n },\r\n moveFolder (state, payload) {\r\n let { items } = state;\r\n \r\n if (payload.parentFolderUUID === \"top\") {\r\n payload.findFolder.returnedItem.folder = \"No Folder\";\r\n // console.info(\"Going to push...\", payload.findFolder.returnedItem);\r\n // console.info(\"Containing these items...\", payload.findFolder.returnedItem.items);\r\n\r\n items.push(payload.findFolder.returnedItem);\r\n Vue.set(state, 'items', items);\r\n \r\n } else if (payload.findParentFolder) { \r\n // console.info(\"Going to push...\", payload.findFolder.returnedItem);\r\n // console.info(\"Containing these items...\", payload.findFolder.returnedItem.items);\r\n // console.info(\"Into...\", payload.findParentFolder.returnedItem);\r\n\r\n payload.findFolder.returnedItem.folder = payload.findParentFolder.name;\r\n payload.findParentFolder.returnedItem.items.push(payload.findFolder.returnedItem);\r\n Vue.set(state,'items', items);\r\n }\r\n },\r\n moveItem (state, payload) {\r\n let { items } = state;\r\n \r\n if (payload.parentFolderUUID === \"top\") {\r\n payload.findItem.returnedItem.folder = \"No Folder\";\r\n // console.info(\"Going to push...\", payload.findFolder.returnedItem);\r\n // console.info(\"Containing these items...\", payload.findFolder.returnedItem.items);\r\n\r\n items.push(payload.findItem.returnedItem);\r\n Vue.set(state,'items', items);\r\n \r\n } else if (payload.findParentFolder) { \r\n // console.info(\"Going to push...\", payload.findFolder.returnedItem);\r\n // console.info(\"Containing these items...\", payload.findFolder.returnedItem.items);\r\n // console.info(\"Into...\", payload.findParentFolder.returnedItem);\r\n\r\n payload.findItem.returnedItem.folder = payload.findParentFolder.name;\r\n payload.findParentFolder.returnedItem.items.push(payload.findItem.returnedItem);\r\n Vue.set(state,'items', items);\r\n }\r\n }\r\n }\r\n})\r\n","/*\r\n main.js\r\n\r\n Created by Kalila L. on 7 Apr 2020\r\n Copyright 2020 Vircadia and contributors.\r\n \r\n Distributed under the Apache License, Version 2.0.\r\n See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html\r\n*/\r\n\r\nimport Vue from 'vue'\r\nimport App from './App.vue'\r\nimport vuetify from './plugins/vuetify';\r\nimport { store } from './plugins/store';\r\n\r\nVue.config.productionTip = false;\r\n\r\nwindow.vm = new Vue({\r\n vuetify,\r\n store,\r\n render: h => h(App)\r\n}).$mount('#app');\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/scripts/system/inventory/dist/js/chunk-vendors.a0f21a27.js b/scripts/system/inventory/dist/js/chunk-vendors.a0f21a27.js new file mode 100644 index 0000000000..82d8c35668 --- /dev/null +++ b/scripts/system/inventory/dist/js/chunk-vendors.a0f21a27.js @@ -0,0 +1,21 @@ +(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-vendors"],{"00ee":function(t,e,n){var i=n("b622"),r=i("toStringTag"),o={};o[r]="z",t.exports="[object z]"===String(o)},"0366":function(t,e,n){var i=n("1c0b");t.exports=function(t,e,n){if(i(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,i){return t.call(e,n,i)};case 3:return function(n,i,r){return t.call(e,n,i,r)}}return function(){return t.apply(e,arguments)}}},"0481":function(t,e,n){"use strict";var i=n("23e7"),r=n("a2bf"),o=n("7b0b"),a=n("50c4"),s=n("a691"),c=n("65f0");i({target:"Array",proto:!0},{flat:function(){var t=arguments.length?arguments[0]:void 0,e=o(this),n=a(e.length),i=c(e,0);return i.length=r(i,e,e,n,0,void 0===t?1:s(t)),i}})},"0538":function(t,e,n){"use strict";var i=n("1c0b"),r=n("861d"),o=[].slice,a={},s=function(t,e,n){if(!(e in a)){for(var i=[],r=0;r0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length,i=new Array(n>1?n-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:"top center 0",n=arguments.length>2?arguments[2]:void 0;return{name:t,functional:!0,props:{group:{type:Boolean,default:!1},hideOnLeave:{type:Boolean,default:!1},leaveAbsolute:{type:Boolean,default:!1},mode:{type:String,default:n},origin:{type:String,default:e}},render:function(e,n){var o="transition".concat(n.props.group?"-group":""),a={props:{name:t,mode:n.props.mode},on:{beforeEnter:function(t){t.style.transformOrigin=n.props.origin,t.style.webkitTransformOrigin=n.props.origin}}};return n.props.leaveAbsolute&&(a.on.leave=r(a.on.leave,(function(t){return t.style.position="absolute"}))),n.props.hideOnLeave&&(a.on.leave=r(a.on.leave,(function(t){return t.style.display="none"}))),e(o,Object(i["a"])(n.data,a),n.children)}}}function a(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"in-out";return{name:t,functional:!0,props:{mode:{type:String,default:n}},render:function(n,r){return n("transition",Object(i["a"])(r.data,{props:{name:t},on:e}),r.children)}}}var s=n("ade3"),c=n("80d2"),l=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=e?"width":"height",i="offset".concat(Object(c["y"])(n));return{beforeEnter:function(t){t._parent=t.parentNode,t._initialStyle=Object(s["a"])({transition:t.style.transition,visibility:t.style.visibility,overflow:t.style.overflow},n,t.style[n])},enter:function(e){var r=e._initialStyle,o="".concat(e[i],"px");e.style.setProperty("transition","none","important"),e.style.visibility="hidden",e.style.visibility=r.visibility,e.style.overflow="hidden",e.style[n]="0",e.offsetHeight,e.style.transition=r.transition,t&&e._parent&&e._parent.classList.add(t),requestAnimationFrame((function(){e.style[n]=o}))},afterEnter:o,enterCancelled:o,leave:function(t){t._initialStyle=Object(s["a"])({transition:"",visibility:"",overflow:t.style.overflow},n,t.style[n]),t.style.overflow="hidden",t.style[n]="".concat(t[i],"px"),t.offsetHeight,requestAnimationFrame((function(){return t.style[n]="0"}))},afterLeave:r,leaveCancelled:r};function r(e){t&&e._parent&&e._parent.classList.remove(t),o(e)}function o(t){var e=t._initialStyle[n];t.style.overflow=t._initialStyle.overflow,null!=e&&(t.style[n]=e),delete t._initialStyle}},u=(o("carousel-transition"),o("carousel-reverse-transition"),o("tab-transition"),o("tab-reverse-transition"),o("menu-transition"),o("fab-transition","center center","out-in"),o("dialog-transition"),o("dialog-bottom-transition"),o("fade-transition")),h=o("scale-transition"),f=(o("scroll-x-transition"),o("scroll-x-reverse-transition"),o("scroll-y-transition"),o("scroll-y-reverse-transition"),o("slide-x-transition")),d=(o("slide-x-reverse-transition"),o("slide-y-transition"),o("slide-y-reverse-transition"),a("expand-transition",l())),p=a("expand-x-transition",l("",!0))},"07ac":function(t,e,n){var i=n("23e7"),r=n("6f53").values;i({target:"Object",stat:!0},{values:function(t){return r(t)}})},"0bc6":function(t,e,n){},"0cfb":function(t,e,n){var i=n("83ab"),r=n("d039"),o=n("cc12");t.exports=!i&&!r((function(){return 7!=Object.defineProperty(o("div"),"a",{get:function(){return 7}}).a}))},"0d3b":function(t,e,n){var i=n("d039"),r=n("b622"),o=n("c430"),a=r("iterator");t.exports=!i((function(){var t=new URL("b?a=1&b=2&c=3","http://a"),e=t.searchParams,n="";return t.pathname="c%20d",e.forEach((function(t,i){e["delete"]("b"),n+=i+t})),o&&!t.toJSON||!e.sort||"http://a/c%20d?a=1&c=3"!==t.href||"3"!==e.get("c")||"a=1"!==String(new URLSearchParams("?a=1"))||!e[a]||"a"!==new URL("https://a@b").username||"b"!==new URLSearchParams(new URLSearchParams("a=b")).get("a")||"xn--e1aybc"!==new URL("http://тест").host||"#%D0%B1"!==new URL("http://a#б").hash||"a1c3"!==n||"x"!==new URL("http://x",void 0).host}))},"10d2":function(t,e,n){"use strict";var i=n("8dd9");e["a"]=i["a"]},1148:function(t,e,n){"use strict";var i=n("a691"),r=n("1d80");t.exports="".repeat||function(t){var e=String(r(this)),n="",o=i(t);if(o<0||o==1/0)throw RangeError("Wrong number of repetitions");for(;o>0;(o>>>=1)&&(e+=e))1&o&&(n+=e);return n}},1276:function(t,e,n){"use strict";var i=n("d784"),r=n("44e7"),o=n("825a"),a=n("1d80"),s=n("4840"),c=n("8aa5"),l=n("50c4"),u=n("14c3"),h=n("9263"),f=n("d039"),d=[].push,p=Math.min,v=4294967295,m=!f((function(){return!RegExp(v,"y")}));i("split",2,(function(t,e,n){var i;return i="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var i=String(a(this)),o=void 0===n?v:n>>>0;if(0===o)return[];if(void 0===t)return[i];if(!r(t))return e.call(i,t,o);var s,c,l,u=[],f=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),p=0,m=new RegExp(t.source,f+"g");while(s=h.call(m,i)){if(c=m.lastIndex,c>p&&(u.push(i.slice(p,s.index)),s.length>1&&s.index=o))break;m.lastIndex===s.index&&m.lastIndex++}return p===i.length?!l&&m.test("")||u.push(""):u.push(i.slice(p)),u.length>o?u.slice(0,o):u}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var r=a(this),o=void 0==e?void 0:e[t];return void 0!==o?o.call(e,r,n):i.call(String(r),e,n)},function(t,r){var a=n(i,t,this,r,i!==e);if(a.done)return a.value;var h=o(t),f=String(this),d=s(h,RegExp),g=h.unicode,b=(h.ignoreCase?"i":"")+(h.multiline?"m":"")+(h.unicode?"u":"")+(m?"y":"g"),y=new d(m?h:"^(?:"+h.source+")",b),w=void 0===r?v:r>>>0;if(0===w)return[];if(0===f.length)return null===u(y,f)?[f]:[];var x=0,O=0,_=[];while(O4}(function(t){t["xSmall"]="12px",t["small"]="16px",t["default"]="24px",t["medium"]="28px",t["large"]="36px",t["xLarge"]="40px"})(i||(i={}));var p=Object(h["a"])(o["a"],a["a"],s["a"],c["a"]).extend({name:"v-icon",props:{dense:Boolean,disabled:Boolean,left:Boolean,right:Boolean,size:[Number,String],tag:{type:String,required:!1,default:"i"}},computed:{medium:function(){return!1},hasClickListener:function(){return Boolean(this.listeners$.click||this.listeners$["!click"])}},methods:{getIcon:function(){var t="";return this.$slots.default&&(t=this.$slots.default[0].text.trim()),Object(l["x"])(this,t)},getSize:function(){var t={xSmall:this.xSmall,small:this.small,medium:this.medium,large:this.large,xLarge:this.xLarge},e=Object(l["t"])(t).find((function(e){return t[e]}));return e&&i[e]||Object(l["f"])(this.size)},getDefaultData:function(){var t={staticClass:"v-icon notranslate",class:{"v-icon--disabled":this.disabled,"v-icon--left":this.left,"v-icon--link":this.hasClickListener,"v-icon--right":this.right,"v-icon--dense":this.dense},attrs:Object(r["a"])({"aria-hidden":!this.hasClickListener,disabled:this.hasClickListener&&this.disabled,type:this.hasClickListener?"button":void 0},this.attrs$),on:this.listeners$};return t},applyColors:function(t){t.class=Object(r["a"])(Object(r["a"])({},t.class),this.themeClasses),this.setTextColor(this.color,t)},renderFontIcon:function(t,e){var n=[],i=this.getDefaultData(),r="material-icons",o=t.indexOf("-"),a=o<=-1;a?n.push(t):(r=t.slice(0,o),f(r)&&(r="")),i.class[r]=!0,i.class[t]=!a;var s=this.getSize();return s&&(i.style={fontSize:s}),this.applyColors(i),e(this.hasClickListener?"button":this.tag,i,n)},renderSvgIcon:function(t,e){var n=this.getSize(),i=Object(r["a"])(Object(r["a"])({},this.getDefaultData()),{},{style:n?{fontSize:n,height:n,width:n}:void 0});i.class["v-icon--svg"]=!0,this.applyColors(i);var o={attrs:{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",height:n||"24",width:n||"24",role:"img","aria-hidden":!0}};return e(this.hasClickListener?"button":"span",i,[e("svg",o,[e("path",{attrs:{d:t}})])])},renderSvgIconComponent:function(t,e){var n=this.getDefaultData();n.class["v-icon--is-component"]=!0;var i=this.getSize();i&&(n.style={fontSize:i,height:i,width:i}),this.applyColors(n);var r=t.component;return n.props=t.props,n.nativeOn=n.on,e(r,n)}},render:function(t){var e=this.getIcon();return"string"===typeof e?d(e)?this.renderSvgIcon(e,t):this.renderFontIcon(e,t):this.renderSvgIconComponent(e,t)}});e["a"]=u["a"].extend({name:"v-icon",$_wrapperFor:p,functional:!0,render:function(t,e){var n=e.data,i=e.children,r="";return n.domProps&&(r=n.domProps.textContent||n.domProps.innerHTML||r,delete n.domProps.textContent,delete n.domProps.innerHTML),t(p,n,r?[r]:i)}})},"13d5":function(t,e,n){"use strict";var i=n("23e7"),r=n("d58f").left,o=n("a640"),a=n("ae40"),s=o("reduce"),c=a("reduce",{1:0});i({target:"Array",proto:!0,forced:!s||!c},{reduce:function(t){return r(this,t,arguments.length,arguments.length>1?arguments[1]:void 0)}})},"14c3":function(t,e,n){var i=n("c6b6"),r=n("9263");t.exports=function(t,e){var n=t.exec;if("function"===typeof n){var o=n.call(t,e);if("object"!==typeof o)throw TypeError("RegExp exec method returned something other than an Object or null");return o}if("RegExp"!==i(t))throw TypeError("RegExp#exec called on incompatible receiver");return r.call(t,e)}},"159b":function(t,e,n){var i=n("da84"),r=n("fdbc"),o=n("17c2"),a=n("9112");for(var s in r){var c=i[s],l=c&&c.prototype;if(l&&l.forEach!==o)try{a(l,"forEach",o)}catch(u){l.forEach=o}}},"15fd":function(t,e,n){"use strict";n.d(e,"a",(function(){return r}));n("a4d3"),n("c975"),n("b64b");function i(t,e){if(null==t)return{};var n,i,r={},o=Object.keys(t);for(i=0;i=0||(r[n]=t[n]);return r}function r(t,e){if(null==t)return{};var n,r,o=i(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(o[n]=t[n])}return o}},"166a":function(t,e,n){},"169a":function(t,e,n){"use strict";n("7db0"),n("caad"),n("45fc"),n("a9e3"),n("2532"),n("498a");var i=n("5530"),r=n("2909"),o=n("ade3"),a=(n("368e"),n("480e")),s=n("4ad4"),c=n("b848"),l=n("75eb"),u=n("e707"),h=n("e4d3"),f=n("21be"),d=n("f2e7"),p=n("a293"),v=n("58df"),m=n("d9bd"),g=n("80d2"),b=Object(v["a"])(s["a"],c["a"],l["a"],u["a"],h["a"],f["a"],d["a"]);e["a"]=b.extend({name:"v-dialog",directives:{ClickOutside:p["a"]},props:{dark:Boolean,disabled:Boolean,fullscreen:Boolean,light:Boolean,maxWidth:{type:[String,Number],default:"none"},noClickAnimation:Boolean,origin:{type:String,default:"center center"},persistent:Boolean,retainFocus:{type:Boolean,default:!0},scrollable:Boolean,transition:{type:[String,Boolean],default:"dialog-transition"},width:{type:[String,Number],default:"auto"}},data:function(){return{activatedBy:null,animate:!1,animateTimeout:-1,isActive:!!this.value,stackMinZIndex:200}},computed:{classes:function(){var t;return t={},Object(o["a"])(t,"v-dialog ".concat(this.contentClass).trim(),!0),Object(o["a"])(t,"v-dialog--active",this.isActive),Object(o["a"])(t,"v-dialog--persistent",this.persistent),Object(o["a"])(t,"v-dialog--fullscreen",this.fullscreen),Object(o["a"])(t,"v-dialog--scrollable",this.scrollable),Object(o["a"])(t,"v-dialog--animated",this.animate),t},contentClasses:function(){return{"v-dialog__content":!0,"v-dialog__content--active":this.isActive}},hasActivator:function(){return Boolean(!!this.$slots.activator||!!this.$scopedSlots.activator)}},watch:{isActive:function(t){t?(this.show(),this.hideScroll()):(this.removeOverlay(),this.unbind())},fullscreen:function(t){this.isActive&&(t?(this.hideScroll(),this.removeOverlay(!1)):(this.showScroll(),this.genOverlay()))}},created:function(){this.$attrs.hasOwnProperty("full-width")&&Object(m["e"])("full-width",this)},beforeMount:function(){var t=this;this.$nextTick((function(){t.isBooted=t.isActive,t.isActive&&t.show()}))},beforeDestroy:function(){"undefined"!==typeof window&&this.unbind()},methods:{animateClick:function(){var t=this;this.animate=!1,this.$nextTick((function(){t.animate=!0,window.clearTimeout(t.animateTimeout),t.animateTimeout=window.setTimeout((function(){return t.animate=!1}),150)}))},closeConditional:function(t){var e=t.target;return!(this._isDestroyed||!this.isActive||this.$refs.content.contains(e)||this.overlay&&e&&!this.overlay.$el.contains(e))&&this.activeZIndex>=this.getMaxZIndex()},hideScroll:function(){this.fullscreen?document.documentElement.classList.add("overflow-y-hidden"):u["a"].options.methods.hideScroll.call(this)},show:function(){var t=this;!this.fullscreen&&!this.hideOverlay&&this.genOverlay(),this.$nextTick((function(){t.$refs.content.focus(),t.bind()}))},bind:function(){window.addEventListener("focusin",this.onFocusin)},unbind:function(){window.removeEventListener("focusin",this.onFocusin)},onClickOutside:function(t){this.$emit("click:outside",t),this.persistent?this.noClickAnimation||this.animateClick():this.isActive=!1},onKeydown:function(t){if(t.keyCode===g["s"].esc&&!this.getOpenDependents().length)if(this.persistent)this.noClickAnimation||this.animateClick();else{this.isActive=!1;var e=this.getActivator();this.$nextTick((function(){return e&&e.focus()}))}this.$emit("keydown",t)},onFocusin:function(t){if(t&&this.retainFocus){var e=t.target;if(e&&![document,this.$refs.content].includes(e)&&!this.$refs.content.contains(e)&&this.activeZIndex>=this.getMaxZIndex()&&!this.getOpenDependentElements().some((function(t){return t.contains(e)}))){var n=this.$refs.content.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),i=Object(r["a"])(n).find((function(t){return!t.hasAttribute("disabled")}));i&&i.focus()}}},genContent:function(){var t=this;return this.showLazyContent((function(){return[t.$createElement(a["a"],{props:{root:!0,light:t.light,dark:t.dark}},[t.$createElement("div",{class:t.contentClasses,attrs:Object(i["a"])({role:"document",tabindex:t.isActive?0:void 0},t.getScopeIdAttrs()),on:{keydown:t.onKeydown},style:{zIndex:t.activeZIndex},ref:"content"},[t.genTransition()])])]}))},genTransition:function(){var t=this.genInnerContent();return this.transition?this.$createElement("transition",{props:{name:this.transition,origin:this.origin,appear:!0}},[t]):t},genInnerContent:function(){var t={class:this.classes,ref:"dialog",directives:[{name:"click-outside",value:{handler:this.onClickOutside,closeConditional:this.closeConditional,include:this.getOpenDependentElements}},{name:"show",value:this.isActive}],style:{transformOrigin:this.origin}};return this.fullscreen||(t.style=Object(i["a"])(Object(i["a"])({},t.style),{},{maxWidth:"none"===this.maxWidth?void 0:Object(g["f"])(this.maxWidth),width:"auto"===this.width?void 0:Object(g["f"])(this.width)})),this.$createElement("div",t,this.getContentSlot())}},render:function(t){return t("div",{staticClass:"v-dialog__container",class:{"v-dialog__container--attached":""===this.attach||!0===this.attach||"attach"===this.attach},attrs:{role:"dialog"}},[this.genActivator(),this.genContent()])}})},"16b7":function(t,e,n){"use strict";n("a9e3");var i=n("2b0e");e["a"]=i["a"].extend().extend({name:"delayable",props:{openDelay:{type:[Number,String],default:0},closeDelay:{type:[Number,String],default:0}},data:function(){return{openTimeout:void 0,closeTimeout:void 0}},methods:{clearDelay:function(){clearTimeout(this.openTimeout),clearTimeout(this.closeTimeout)},runDelay:function(t,e){var n=this;this.clearDelay();var i=parseInt(this["".concat(t,"Delay")],10);this["".concat(t,"Timeout")]=setTimeout(e||function(){n.isActive={open:!0,close:!1}[t]},i)}}})},"17c2":function(t,e,n){"use strict";var i=n("b727").forEach,r=n("a640"),o=n("ae40"),a=r("forEach"),s=o("forEach");t.exports=a&&s?[].forEach:function(t){return i(this,t,arguments.length>1?arguments[1]:void 0)}},1800:function(t,e,n){"use strict";n("4de4");var i=n("2b0e");e["a"]=i["a"].extend({name:"v-list-item-action",functional:!0,render:function(t,e){var n=e.data,i=e.children,r=void 0===i?[]:i;n.staticClass=n.staticClass?"v-list-item__action ".concat(n.staticClass):"v-list-item__action";var o=r.filter((function(t){return!1===t.isComment&&" "!==t.text}));return o.length>1&&(n.staticClass+=" v-list-item__action--stack"),t("div",n,r)}})},"18a5":function(t,e,n){"use strict";var i=n("23e7"),r=n("857a"),o=n("af03");i({target:"String",proto:!0,forced:o("anchor")},{anchor:function(t){return r(this,"a","name",t)}})},"19aa":function(t,e){t.exports=function(t,e,n){if(!(t instanceof e))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return t}},"1b2c":function(t,e,n){},"1baa":function(t,e,n){"use strict";var i=n("5530"),r=(n("899c"),n("604c")),o=n("a9ad"),a=n("58df");e["a"]=Object(a["a"])(r["a"],o["a"]).extend({name:"v-list-item-group",provide:function(){return{isInGroup:!0,listItemGroup:this}},computed:{classes:function(){return Object(i["a"])(Object(i["a"])({},r["a"].options.computed.classes.call(this)),{},{"v-list-item-group":!0})}},methods:{genData:function(){return this.setTextColor(this.color,Object(i["a"])(Object(i["a"])({},r["a"].options.methods.genData.call(this)),{},{attrs:{role:"listbox"}}))}}})},"1be4":function(t,e,n){var i=n("d066");t.exports=i("document","documentElement")},"1c0b":function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},"1c7e":function(t,e,n){var i=n("b622"),r=i("iterator"),o=!1;try{var a=0,s={next:function(){return{done:!!a++}},return:function(){o=!0}};s[r]=function(){return this},Array.from(s,(function(){throw 2}))}catch(c){}t.exports=function(t,e){if(!e&&!o)return!1;var n=!1;try{var i={};i[r]=function(){return{next:function(){return{done:n=!0}}}},t(i)}catch(c){}return n}},"1c87":function(t,e,n){"use strict";n("99af"),n("ac1f"),n("5319"),n("498a"),n("9911");var i=n("ade3"),r=n("5530"),o=n("2b0e"),a=n("5607"),s=n("80d2");e["a"]=o["a"].extend({name:"routable",directives:{Ripple:a["a"]},props:{activeClass:String,append:Boolean,disabled:Boolean,exact:{type:Boolean,default:void 0},exactActiveClass:String,link:Boolean,href:[String,Object],to:[String,Object],nuxt:Boolean,replace:Boolean,ripple:{type:[Boolean,Object],default:null},tag:String,target:String},data:function(){return{isActive:!1,proxyClass:""}},computed:{classes:function(){var t={};return this.to||(this.activeClass&&(t[this.activeClass]=this.isActive),this.proxyClass&&(t[this.proxyClass]=this.isActive)),t},computedRipple:function(){return null!=this.ripple?this.ripple:!this.disabled&&this.isClickable},isClickable:function(){return!this.disabled&&Boolean(this.isLink||this.$listeners.click||this.$listeners["!click"]||this.$attrs.tabindex)},isLink:function(){return this.to||this.href||this.link},styles:function(){return{}}},watch:{$route:"onRouteChange"},methods:{click:function(t){this.$emit("click",t)},generateRouteLink:function(){var t,e,n=this.exact,o=(t={attrs:{tabindex:"tabindex"in this.$attrs?this.$attrs.tabindex:void 0},class:this.classes,style:this.styles,props:{},directives:[{name:"ripple",value:this.computedRipple}]},Object(i["a"])(t,this.to?"nativeOn":"on",Object(r["a"])(Object(r["a"])({},this.$listeners),{},{click:this.click})),Object(i["a"])(t,"ref","link"),t);if("undefined"===typeof this.exact&&(n="/"===this.to||this.to===Object(this.to)&&"/"===this.to.path),this.to){var a=this.activeClass,s=this.exactActiveClass||a;this.proxyClass&&(a="".concat(a," ").concat(this.proxyClass).trim(),s="".concat(s," ").concat(this.proxyClass).trim()),e=this.nuxt?"nuxt-link":"router-link",Object.assign(o.props,{to:this.to,exact:n,activeClass:a,exactActiveClass:s,append:this.append,replace:this.replace})}else e=(this.href?"a":this.tag)||"div","a"===e&&this.href&&(o.attrs.href=this.href);return this.target&&(o.attrs.target=this.target),{tag:e,data:o}},onRouteChange:function(){var t=this;if(this.to&&this.$refs.link&&this.$route){var e="".concat(this.activeClass," ").concat(this.proxyClass||"").trim(),n="_vnode.data.class.".concat(e);this.$nextTick((function(){Object(s["m"])(t.$refs.link,n)&&t.toggle()}))}},toggle:function(){}}})},"1cdc":function(t,e,n){var i=n("342f");t.exports=/(iphone|ipod|ipad).*applewebkit/i.test(i)},"1d80":function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},"1dde":function(t,e,n){var i=n("d039"),r=n("b622"),o=n("2d00"),a=r("species");t.exports=function(t){return o>=51||!i((function(){var e=[],n=e.constructor={};return n[a]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},"20f6":function(t,e,n){},"21be":function(t,e,n){"use strict";n("99af"),n("caad"),n("2532");var i=n("2909"),r=n("2b0e"),o=n("80d2");e["a"]=r["a"].extend().extend({name:"stackable",data:function(){return{stackElement:null,stackExclude:null,stackMinZIndex:0,isActive:!1}},computed:{activeZIndex:function(){if("undefined"===typeof window)return 0;var t=this.stackElement||this.$refs.content,e=this.isActive?this.getMaxZIndex(this.stackExclude||[t])+2:Object(o["q"])(t);return null==e?e:parseInt(e)}},methods:{getMaxZIndex:function(){for(var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],e=this.$el,n=[this.stackMinZIndex,Object(o["q"])(e)],r=[].concat(Object(i["a"])(document.getElementsByClassName("v-menu__content--active")),Object(i["a"])(document.getElementsByClassName("v-dialog__content--active"))),a=0;ap;p++)if(m=u?y(i(b=t[p])[0],b[1]):y(t[p]),m&&m instanceof l)return m;return new l(!1)}f=d.call(t)}g=f.next;while(!(b=g.call(f)).done)if(m=c(f,y,b.value,u),"object"==typeof m&&m&&m instanceof l)return m;return new l(!1)};u.stop=function(t){return new l(!0,t)}},"23cb":function(t,e,n){var i=n("a691"),r=Math.max,o=Math.min;t.exports=function(t,e){var n=i(t);return n<0?r(n+e,0):o(n,e)}},"23e7":function(t,e,n){var i=n("da84"),r=n("06cf").f,o=n("9112"),a=n("6eeb"),s=n("ce4e"),c=n("e893"),l=n("94ca");t.exports=function(t,e){var n,u,h,f,d,p,v=t.target,m=t.global,g=t.stat;if(u=m?i:g?i[v]||s(v,{}):(i[v]||{}).prototype,u)for(h in e){if(d=e[h],t.noTargetGet?(p=r(u,h),f=p&&p.value):f=u[h],n=l(m?h:v+(g?".":"#")+h,t.forced),!n&&void 0!==f){if(typeof d===typeof f)continue;c(d,f)}(t.sham||f&&f.sham)&&o(d,"sham",!0),a(u,h,d,t)}}},"241c":function(t,e,n){var i=n("ca84"),r=n("7839"),o=r.concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return i(t,o)}},"24b2":function(t,e,n){"use strict";n("a9e3");var i=n("80d2"),r=n("2b0e");e["a"]=r["a"].extend({name:"measurable",props:{height:[Number,String],maxHeight:[Number,String],maxWidth:[Number,String],minHeight:[Number,String],minWidth:[Number,String],width:[Number,String]},computed:{measurableStyles:function(){var t={},e=Object(i["f"])(this.height),n=Object(i["f"])(this.minHeight),r=Object(i["f"])(this.minWidth),o=Object(i["f"])(this.maxHeight),a=Object(i["f"])(this.maxWidth),s=Object(i["f"])(this.width);return e&&(t.height=e),n&&(t.minHeight=n),r&&(t.minWidth=r),o&&(t.maxHeight=o),a&&(t.maxWidth=a),s&&(t.width=s),t}}})},2532:function(t,e,n){"use strict";var i=n("23e7"),r=n("5a34"),o=n("1d80"),a=n("ab13");i({target:"String",proto:!0,forced:!a("includes")},{includes:function(t){return!!~String(o(this)).indexOf(r(t),arguments.length>1?arguments[1]:void 0)}})},"25a8":function(t,e,n){},"25f0":function(t,e,n){"use strict";var i=n("6eeb"),r=n("825a"),o=n("d039"),a=n("ad6d"),s="toString",c=RegExp.prototype,l=c[s],u=o((function(){return"/a/b"!=l.call({source:"a",flags:"b"})})),h=l.name!=s;(u||h)&&i(RegExp.prototype,s,(function(){var t=r(this),e=String(t.source),n=t.flags,i=String(void 0===n&&t instanceof RegExp&&!("flags"in c)?a.call(t):n);return"/"+e+"/"+i}),{unsafe:!0})},2626:function(t,e,n){"use strict";var i=n("d066"),r=n("9bf2"),o=n("b622"),a=n("83ab"),s=o("species");t.exports=function(t){var e=i(t),n=r.f;a&&e&&!e[s]&&n(e,s,{configurable:!0,get:function(){return this}})}},2877:function(t,e,n){"use strict";function i(t,e,n,i,r,o,a,s){var c,l="function"===typeof t?t.options:t;if(e&&(l.render=e,l.staticRenderFns=n,l._compiled=!0),i&&(l.functional=!0),o&&(l._scopeId="data-v-"+o),a?(c=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"===typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),r&&r.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(a)},l._ssrRegister=c):r&&(c=s?function(){r.call(this,(l.functional?this.parent:this).$root.$options.shadowRoot)}:r),c)if(l.functional){l._injectStyles=c;var u=l.render;l.render=function(t,e){return c.call(e),u(t,e)}}else{var h=l.beforeCreate;l.beforeCreate=h?[].concat(h,c):[c]}return{exports:t,options:l}}n.d(e,"a",(function(){return i}))},2909:function(t,e,n){"use strict";n.d(e,"a",(function(){return c}));var i=n("6b75");function r(t){if(Array.isArray(t))return Object(i["a"])(t)}n("a4d3"),n("e01a"),n("d28b"),n("a630"),n("d3b7"),n("3ca3"),n("ddb0");function o(t){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(t))return Array.from(t)}var a=n("06c5");function s(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function c(t){return r(t)||o(t)||Object(a["a"])(t)||s()}},"297c":function(t,e,n){"use strict";n("a9e3");var i=n("2b0e"),r=(n("c7cd"),n("5530")),o=n("ade3"),a=(n("6ece"),n("0789")),s=n("a9ad"),c=n("fe6c"),l=n("a452"),u=n("7560"),h=n("80d2"),f=n("58df"),d=Object(f["a"])(s["a"],Object(c["b"])(["absolute","fixed","top","bottom"]),l["a"],u["a"]),p=d.extend({name:"v-progress-linear",props:{active:{type:Boolean,default:!0},backgroundColor:{type:String,default:null},backgroundOpacity:{type:[Number,String],default:null},bufferValue:{type:[Number,String],default:100},color:{type:String,default:"primary"},height:{type:[Number,String],default:4},indeterminate:Boolean,query:Boolean,reverse:Boolean,rounded:Boolean,stream:Boolean,striped:Boolean,value:{type:[Number,String],default:0}},data:function(){return{internalLazyValue:this.value||0}},computed:{__cachedBackground:function(){return this.$createElement("div",this.setBackgroundColor(this.backgroundColor||this.color,{staticClass:"v-progress-linear__background",style:this.backgroundStyle}))},__cachedBar:function(){return this.$createElement(this.computedTransition,[this.__cachedBarType])},__cachedBarType:function(){return this.indeterminate?this.__cachedIndeterminate:this.__cachedDeterminate},__cachedBuffer:function(){return this.$createElement("div",{staticClass:"v-progress-linear__buffer",style:this.styles})},__cachedDeterminate:function(){return this.$createElement("div",this.setBackgroundColor(this.color,{staticClass:"v-progress-linear__determinate",style:{width:Object(h["f"])(this.normalizedValue,"%")}}))},__cachedIndeterminate:function(){return this.$createElement("div",{staticClass:"v-progress-linear__indeterminate",class:{"v-progress-linear__indeterminate--active":this.active}},[this.genProgressBar("long"),this.genProgressBar("short")])},__cachedStream:function(){return this.stream?this.$createElement("div",this.setTextColor(this.color,{staticClass:"v-progress-linear__stream",style:{width:Object(h["f"])(100-this.normalizedBuffer,"%")}})):null},backgroundStyle:function(){var t,e=null==this.backgroundOpacity?this.backgroundColor?1:.3:parseFloat(this.backgroundOpacity);return t={opacity:e},Object(o["a"])(t,this.isReversed?"right":"left",Object(h["f"])(this.normalizedValue,"%")),Object(o["a"])(t,"width",Object(h["f"])(this.normalizedBuffer-this.normalizedValue,"%")),t},classes:function(){return Object(r["a"])({"v-progress-linear--absolute":this.absolute,"v-progress-linear--fixed":this.fixed,"v-progress-linear--query":this.query,"v-progress-linear--reactive":this.reactive,"v-progress-linear--reverse":this.isReversed,"v-progress-linear--rounded":this.rounded,"v-progress-linear--striped":this.striped},this.themeClasses)},computedTransition:function(){return this.indeterminate?a["c"]:a["e"]},isReversed:function(){return this.$vuetify.rtl!==this.reverse},normalizedBuffer:function(){return this.normalize(this.bufferValue)},normalizedValue:function(){return this.normalize(this.internalLazyValue)},reactive:function(){return Boolean(this.$listeners.change)},styles:function(){var t={};return this.active||(t.height=0),this.indeterminate||100===parseFloat(this.normalizedBuffer)||(t.width=Object(h["f"])(this.normalizedBuffer,"%")),t}},methods:{genContent:function(){var t=Object(h["o"])(this,"default",{value:this.internalLazyValue});return t?this.$createElement("div",{staticClass:"v-progress-linear__content"},t):null},genListeners:function(){var t=this.$listeners;return this.reactive&&(t.click=this.onClick),t},genProgressBar:function(t){return this.$createElement("div",this.setBackgroundColor(this.color,{staticClass:"v-progress-linear__indeterminate",class:Object(o["a"])({},t,!0)}))},onClick:function(t){if(this.reactive){var e=this.$el.getBoundingClientRect(),n=e.width;this.internalValue=t.offsetX/n*100}},normalize:function(t){return t<0?0:t>100?100:parseFloat(t)}},render:function(t){var e={staticClass:"v-progress-linear",attrs:{role:"progressbar","aria-valuemin":0,"aria-valuemax":this.normalizedBuffer,"aria-valuenow":this.indeterminate?void 0:this.normalizedValue},class:this.classes,style:{bottom:this.bottom?0:void 0,height:this.active?Object(h["f"])(this.height):0,top:this.top?0:void 0},on:this.genListeners()};return t("div",e,[this.__cachedStream,this.__cachedBackground,this.__cachedBuffer,this.__cachedBar,this.genContent()])}}),v=p;e["a"]=i["a"].extend().extend({name:"loadable",props:{loading:{type:[Boolean,String],default:!1},loaderHeight:{type:[Number,String],default:2}},methods:{genProgress:function(){return!1===this.loading?null:this.$slots.progress||this.$createElement(v,{props:{absolute:!0,color:!0===this.loading||""===this.loading?this.color||"primary":this.loading,height:this.loaderHeight,indeterminate:!0}})}}})},"2a7f":function(t,e,n){"use strict";n.d(e,"a",(function(){return o}));var i=n("71d9"),r=n("80d2"),o=Object(r["h"])("v-toolbar__title"),a=Object(r["h"])("v-toolbar__items");i["a"]},"2b0e":function(t,e,n){"use strict";(function(t){ +/*! + * Vue.js v2.6.11 + * (c) 2014-2019 Evan You + * Released under the MIT License. + */ +var n=Object.freeze({});function i(t){return void 0===t||null===t}function r(t){return void 0!==t&&null!==t}function o(t){return!0===t}function a(t){return!1===t}function s(t){return"string"===typeof t||"number"===typeof t||"symbol"===typeof t||"boolean"===typeof t}function c(t){return null!==t&&"object"===typeof t}var l=Object.prototype.toString;function u(t){return"[object Object]"===l.call(t)}function h(t){return"[object RegExp]"===l.call(t)}function f(t){var e=parseFloat(String(t));return e>=0&&Math.floor(e)===e&&isFinite(t)}function d(t){return r(t)&&"function"===typeof t.then&&"function"===typeof t.catch}function p(t){return null==t?"":Array.isArray(t)||u(t)&&t.toString===l?JSON.stringify(t,null,2):String(t)}function v(t){var e=parseFloat(t);return isNaN(e)?t:e}function m(t,e){for(var n=Object.create(null),i=t.split(","),r=0;r-1)return t.splice(n,1)}}var y=Object.prototype.hasOwnProperty;function w(t,e){return y.call(t,e)}function x(t){var e=Object.create(null);return function(n){var i=e[n];return i||(e[n]=t(n))}}var O=/-(\w)/g,_=x((function(t){return t.replace(O,(function(t,e){return e?e.toUpperCase():""}))})),S=x((function(t){return t.charAt(0).toUpperCase()+t.slice(1)})),C=/\B([A-Z])/g,k=x((function(t){return t.replace(C,"-$1").toLowerCase()}));function j(t,e){function n(n){var i=arguments.length;return i?i>1?t.apply(e,arguments):t.call(e,n):t.call(e)}return n._length=t.length,n}function A(t,e){return t.bind(e)}var $=Function.prototype.bind?A:j;function E(t,e){e=e||0;var n=t.length-e,i=new Array(n);while(n--)i[n]=t[n+e];return i}function T(t,e){for(var n in e)t[n]=e[n];return t}function I(t){for(var e={},n=0;n0,nt=Q&&Q.indexOf("edge/")>0,it=(Q&&Q.indexOf("android"),Q&&/iphone|ipad|ipod|ios/.test(Q)||"ios"===J),rt=(Q&&/chrome\/\d+/.test(Q),Q&&/phantomjs/.test(Q),Q&&Q.match(/firefox\/(\d+)/)),ot={}.watch,at=!1;if(K)try{var st={};Object.defineProperty(st,"passive",{get:function(){at=!0}}),window.addEventListener("test-passive",null,st)}catch(_a){}var ct=function(){return void 0===X&&(X=!K&&!Z&&"undefined"!==typeof t&&(t["process"]&&"server"===t["process"].env.VUE_ENV)),X},lt=K&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__;function ut(t){return"function"===typeof t&&/native code/.test(t.toString())}var ht,ft="undefined"!==typeof Symbol&&ut(Symbol)&&"undefined"!==typeof Reflect&&ut(Reflect.ownKeys);ht="undefined"!==typeof Set&&ut(Set)?Set:function(){function t(){this.set=Object.create(null)}return t.prototype.has=function(t){return!0===this.set[t]},t.prototype.add=function(t){this.set[t]=!0},t.prototype.clear=function(){this.set=Object.create(null)},t}();var dt=L,pt=0,vt=function(){this.id=pt++,this.subs=[]};vt.prototype.addSub=function(t){this.subs.push(t)},vt.prototype.removeSub=function(t){b(this.subs,t)},vt.prototype.depend=function(){vt.target&&vt.target.addDep(this)},vt.prototype.notify=function(){var t=this.subs.slice();for(var e=0,n=t.length;e-1)if(o&&!w(r,"default"))a=!1;else if(""===a||a===k(t)){var c=te(String,r.type);(c<0||s0&&(a=je(a,(e||"")+"_"+n),ke(a[0])&&ke(l)&&(u[c]=Ot(l.text+a[0].text),a.shift()),u.push.apply(u,a)):s(a)?ke(l)?u[c]=Ot(l.text+a):""!==a&&u.push(Ot(a)):ke(a)&&ke(l)?u[c]=Ot(l.text+a.text):(o(t._isVList)&&r(a.tag)&&i(a.key)&&r(e)&&(a.key="__vlist"+e+"_"+n+"__"),u.push(a)));return u}function Ae(t){var e=t.$options.provide;e&&(t._provided="function"===typeof e?e.call(t):e)}function $e(t){var e=Ee(t.$options.inject,t);e&&($t(!1),Object.keys(e).forEach((function(n){Mt(t,n,e[n])})),$t(!0))}function Ee(t,e){if(t){for(var n=Object.create(null),i=ft?Reflect.ownKeys(t):Object.keys(t),r=0;r0,a=t?!!t.$stable:!o,s=t&&t.$key;if(t){if(t._normalized)return t._normalized;if(a&&i&&i!==n&&s===i.$key&&!o&&!i.$hasNormal)return i;for(var c in r={},t)t[c]&&"$"!==c[0]&&(r[c]=Me(e,c,t[c]))}else r={};for(var l in e)l in r||(r[l]=De(e,l));return t&&Object.isExtensible(t)&&(t._normalized=r),U(r,"$stable",a),U(r,"$key",s),U(r,"$hasNormal",o),r}function Me(t,e,n){var i=function(){var t=arguments.length?n.apply(null,arguments):n({});return t=t&&"object"===typeof t&&!Array.isArray(t)?[t]:Ce(t),t&&(0===t.length||1===t.length&&t[0].isComment)?void 0:t};return n.proxy&&Object.defineProperty(t,e,{get:i,enumerable:!0,configurable:!0}),i}function De(t,e){return function(){return t[e]}}function Be(t,e){var n,i,o,a,s;if(Array.isArray(t)||"string"===typeof t)for(n=new Array(t.length),i=0,o=t.length;i1?E(n):n;for(var i=E(arguments,1),r='event handler for "'+t+'"',o=0,a=n.length;odocument.createEvent("Event").timeStamp&&(Xn=function(){return Gn.now()})}function Kn(){var t,e;for(qn=Xn(),Wn=!0,Rn.sort((function(t,e){return t.id-e.id})),Un=0;UnUn&&Rn[n].id>t.id)n--;Rn.splice(n+1,0,t)}else Rn.push(t);Hn||(Hn=!0,pe(Kn))}}var ei=0,ni=function(t,e,n,i,r){this.vm=t,r&&(t._watcher=this),t._watchers.push(this),i?(this.deep=!!i.deep,this.user=!!i.user,this.lazy=!!i.lazy,this.sync=!!i.sync,this.before=i.before):this.deep=this.user=this.lazy=this.sync=!1,this.cb=n,this.id=++ei,this.active=!0,this.dirty=this.lazy,this.deps=[],this.newDeps=[],this.depIds=new ht,this.newDepIds=new ht,this.expression="","function"===typeof e?this.getter=e:(this.getter=q(e),this.getter||(this.getter=L)),this.value=this.lazy?void 0:this.get()};ni.prototype.get=function(){var t;gt(this);var e=this.vm;try{t=this.getter.call(e,e)}catch(_a){if(!this.user)throw _a;ee(_a,e,'getter for watcher "'+this.expression+'"')}finally{this.deep&&me(t),bt(),this.cleanupDeps()}return t},ni.prototype.addDep=function(t){var e=t.id;this.newDepIds.has(e)||(this.newDepIds.add(e),this.newDeps.push(t),this.depIds.has(e)||t.addSub(this))},ni.prototype.cleanupDeps=function(){var t=this.deps.length;while(t--){var e=this.deps[t];this.newDepIds.has(e.id)||e.removeSub(this)}var n=this.depIds;this.depIds=this.newDepIds,this.newDepIds=n,this.newDepIds.clear(),n=this.deps,this.deps=this.newDeps,this.newDeps=n,this.newDeps.length=0},ni.prototype.update=function(){this.lazy?this.dirty=!0:this.sync?this.run():ti(this)},ni.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||c(t)||this.deep){var e=this.value;if(this.value=t,this.user)try{this.cb.call(this.vm,t,e)}catch(_a){ee(_a,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,t,e)}}},ni.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},ni.prototype.depend=function(){var t=this.deps.length;while(t--)this.deps[t].depend()},ni.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||b(this.vm._watchers,this);var t=this.deps.length;while(t--)this.deps[t].removeSub(this);this.active=!1}};var ii={enumerable:!0,configurable:!0,get:L,set:L};function ri(t,e,n){ii.get=function(){return this[e][n]},ii.set=function(t){this[e][n]=t},Object.defineProperty(t,n,ii)}function oi(t){t._watchers=[];var e=t.$options;e.props&&ai(t,e.props),e.methods&&pi(t,e.methods),e.data?si(t):Lt(t._data={},!0),e.computed&&ui(t,e.computed),e.watch&&e.watch!==ot&&vi(t,e.watch)}function ai(t,e){var n=t.$options.propsData||{},i=t._props={},r=t.$options._propKeys=[],o=!t.$parent;o||$t(!1);var a=function(o){r.push(o);var a=Kt(o,e,n,t);Mt(i,o,a),o in t||ri(t,"_props",o)};for(var s in e)a(s);$t(!0)}function si(t){var e=t.$options.data;e=t._data="function"===typeof e?ci(e,t):e||{},u(e)||(e={});var n=Object.keys(e),i=t.$options.props,r=(t.$options.methods,n.length);while(r--){var o=n[r];0,i&&w(i,o)||W(o)||ri(t,"_data",o)}Lt(e,!0)}function ci(t,e){gt();try{return t.call(e,e)}catch(_a){return ee(_a,e,"data()"),{}}finally{bt()}}var li={lazy:!0};function ui(t,e){var n=t._computedWatchers=Object.create(null),i=ct();for(var r in e){var o=e[r],a="function"===typeof o?o:o.get;0,i||(n[r]=new ni(t,a||L,L,li)),r in t||hi(t,r,o)}}function hi(t,e,n){var i=!ct();"function"===typeof n?(ii.get=i?fi(e):di(n),ii.set=L):(ii.get=n.get?i&&!1!==n.cache?fi(e):di(n.get):L,ii.set=n.set||L),Object.defineProperty(t,e,ii)}function fi(t){return function(){var e=this._computedWatchers&&this._computedWatchers[t];if(e)return e.dirty&&e.evaluate(),vt.target&&e.depend(),e.value}}function di(t){return function(){return t.call(this,this)}}function pi(t,e){t.$options.props;for(var n in e)t[n]="function"!==typeof e[n]?L:$(e[n],t)}function vi(t,e){for(var n in e){var i=e[n];if(Array.isArray(i))for(var r=0;r-1)return this;var n=E(arguments,1);return n.unshift(this),"function"===typeof t.install?t.install.apply(t,n):"function"===typeof t&&t.apply(null,n),e.push(t),this}}function Ci(t){t.mixin=function(t){return this.options=Xt(this.options,t),this}}function ki(t){t.cid=0;var e=1;t.extend=function(t){t=t||{};var n=this,i=n.cid,r=t._Ctor||(t._Ctor={});if(r[i])return r[i];var o=t.name||n.options.name;var a=function(t){this._init(t)};return a.prototype=Object.create(n.prototype),a.prototype.constructor=a,a.cid=e++,a.options=Xt(n.options,t),a["super"]=n,a.options.props&&ji(a),a.options.computed&&Ai(a),a.extend=n.extend,a.mixin=n.mixin,a.use=n.use,R.forEach((function(t){a[t]=n[t]})),o&&(a.options.components[o]=a),a.superOptions=n.options,a.extendOptions=t,a.sealedOptions=T({},a.options),r[i]=a,a}}function ji(t){var e=t.options.props;for(var n in e)ri(t.prototype,"_props",n)}function Ai(t){var e=t.options.computed;for(var n in e)hi(t.prototype,n,e[n])}function $i(t){R.forEach((function(e){t[e]=function(t,n){return n?("component"===e&&u(n)&&(n.name=n.name||t,n=this.options._base.extend(n)),"directive"===e&&"function"===typeof n&&(n={bind:n,update:n}),this.options[e+"s"][t]=n,n):this.options[e+"s"][t]}}))}function Ei(t){return t&&(t.Ctor.options.name||t.tag)}function Ti(t,e){return Array.isArray(t)?t.indexOf(e)>-1:"string"===typeof t?t.split(",").indexOf(e)>-1:!!h(t)&&t.test(e)}function Ii(t,e){var n=t.cache,i=t.keys,r=t._vnode;for(var o in n){var a=n[o];if(a){var s=Ei(a.componentOptions);s&&!e(s)&&Li(n,o,i,r)}}}function Li(t,e,n,i){var r=t[e];!r||i&&r.tag===i.tag||r.componentInstance.$destroy(),t[e]=null,b(n,e)}yi(_i),gi(_i),$n(_i),Ln(_i),bn(_i);var Mi=[String,RegExp,Array],Di={name:"keep-alive",abstract:!0,props:{include:Mi,exclude:Mi,max:[String,Number]},created:function(){this.cache=Object.create(null),this.keys=[]},destroyed:function(){for(var t in this.cache)Li(this.cache,t,this.keys)},mounted:function(){var t=this;this.$watch("include",(function(e){Ii(t,(function(t){return Ti(e,t)}))})),this.$watch("exclude",(function(e){Ii(t,(function(t){return!Ti(e,t)}))}))},render:function(){var t=this.$slots.default,e=_n(t),n=e&&e.componentOptions;if(n){var i=Ei(n),r=this,o=r.include,a=r.exclude;if(o&&(!i||!Ti(o,i))||a&&i&&Ti(a,i))return e;var s=this,c=s.cache,l=s.keys,u=null==e.key?n.Ctor.cid+(n.tag?"::"+n.tag:""):e.key;c[u]?(e.componentInstance=c[u].componentInstance,b(l,u),l.push(u)):(c[u]=e,l.push(u),this.max&&l.length>parseInt(this.max)&&Li(c,l[0],l,this._vnode)),e.data.keepAlive=!0}return e||t&&t[0]}},Bi={KeepAlive:Di};function Pi(t){var e={get:function(){return z}};Object.defineProperty(t,"config",e),t.util={warn:dt,extend:T,mergeOptions:Xt,defineReactive:Mt},t.set=Dt,t.delete=Bt,t.nextTick=pe,t.observable=function(t){return Lt(t),t},t.options=Object.create(null),R.forEach((function(e){t.options[e+"s"]=Object.create(null)})),t.options._base=t,T(t.options.components,Bi),Si(t),Ci(t),ki(t),$i(t)}Pi(_i),Object.defineProperty(_i.prototype,"$isServer",{get:ct}),Object.defineProperty(_i.prototype,"$ssrContext",{get:function(){return this.$vnode&&this.$vnode.ssrContext}}),Object.defineProperty(_i,"FunctionalRenderContext",{value:Ze}),_i.version="2.6.11";var Ni=m("style,class"),Vi=m("input,textarea,option,select,progress"),Ri=function(t,e,n){return"value"===n&&Vi(t)&&"button"!==e||"selected"===n&&"option"===t||"checked"===n&&"input"===t||"muted"===n&&"video"===t},Fi=m("contenteditable,draggable,spellcheck"),zi=m("events,caret,typing,plaintext-only"),Hi=function(t,e){return Xi(e)||"false"===e?"false":"contenteditable"===t&&zi(e)?e:"true"},Wi=m("allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,defaultchecked,defaultmuted,defaultselected,defer,disabled,enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,translate,truespeed,typemustmatch,visible"),Ui="http://www.w3.org/1999/xlink",Yi=function(t){return":"===t.charAt(5)&&"xlink"===t.slice(0,5)},qi=function(t){return Yi(t)?t.slice(6,t.length):""},Xi=function(t){return null==t||!1===t};function Gi(t){var e=t.data,n=t,i=t;while(r(i.componentInstance))i=i.componentInstance._vnode,i&&i.data&&(e=Ki(i.data,e));while(r(n=n.parent))n&&n.data&&(e=Ki(e,n.data));return Zi(e.staticClass,e.class)}function Ki(t,e){return{staticClass:Ji(t.staticClass,e.staticClass),class:r(t.class)?[t.class,e.class]:e.class}}function Zi(t,e){return r(t)||r(e)?Ji(t,Qi(e)):""}function Ji(t,e){return t?e?t+" "+e:t:e||""}function Qi(t){return Array.isArray(t)?tr(t):c(t)?er(t):"string"===typeof t?t:""}function tr(t){for(var e,n="",i=0,o=t.length;i-1?sr[t]=e.constructor===window.HTMLUnknownElement||e.constructor===window.HTMLElement:sr[t]=/HTMLUnknownElement/.test(e.toString())}var lr=m("text,number,password,search,email,tel,url");function ur(t){if("string"===typeof t){var e=document.querySelector(t);return e||document.createElement("div")}return t}function hr(t,e){var n=document.createElement(t);return"select"!==t||e.data&&e.data.attrs&&void 0!==e.data.attrs.multiple&&n.setAttribute("multiple","multiple"),n}function fr(t,e){return document.createElementNS(nr[t],e)}function dr(t){return document.createTextNode(t)}function pr(t){return document.createComment(t)}function vr(t,e,n){t.insertBefore(e,n)}function mr(t,e){t.removeChild(e)}function gr(t,e){t.appendChild(e)}function br(t){return t.parentNode}function yr(t){return t.nextSibling}function wr(t){return t.tagName}function xr(t,e){t.textContent=e}function Or(t,e){t.setAttribute(e,"")}var _r=Object.freeze({createElement:hr,createElementNS:fr,createTextNode:dr,createComment:pr,insertBefore:vr,removeChild:mr,appendChild:gr,parentNode:br,nextSibling:yr,tagName:wr,setTextContent:xr,setStyleScope:Or}),Sr={create:function(t,e){Cr(e)},update:function(t,e){t.data.ref!==e.data.ref&&(Cr(t,!0),Cr(e))},destroy:function(t){Cr(t,!0)}};function Cr(t,e){var n=t.data.ref;if(r(n)){var i=t.context,o=t.componentInstance||t.elm,a=i.$refs;e?Array.isArray(a[n])?b(a[n],o):a[n]===o&&(a[n]=void 0):t.data.refInFor?Array.isArray(a[n])?a[n].indexOf(o)<0&&a[n].push(o):a[n]=[o]:a[n]=o}}var kr=new yt("",{},[]),jr=["create","activate","update","remove","destroy"];function Ar(t,e){return t.key===e.key&&(t.tag===e.tag&&t.isComment===e.isComment&&r(t.data)===r(e.data)&&$r(t,e)||o(t.isAsyncPlaceholder)&&t.asyncFactory===e.asyncFactory&&i(e.asyncFactory.error))}function $r(t,e){if("input"!==t.tag)return!0;var n,i=r(n=t.data)&&r(n=n.attrs)&&n.type,o=r(n=e.data)&&r(n=n.attrs)&&n.type;return i===o||lr(i)&&lr(o)}function Er(t,e,n){var i,o,a={};for(i=e;i<=n;++i)o=t[i].key,r(o)&&(a[o]=i);return a}function Tr(t){var e,n,a={},c=t.modules,l=t.nodeOps;for(e=0;ev?(h=i(n[b+1])?null:n[b+1].elm,_(t,h,n,p,b,o)):p>b&&C(e,f,v)}function A(t,e,n,i){for(var o=n;o-1?zr(t,e,n):Wi(e)?Xi(n)?t.removeAttribute(e):(n="allowfullscreen"===e&&"EMBED"===t.tagName?"true":e,t.setAttribute(e,n)):Fi(e)?t.setAttribute(e,Hi(e,n)):Yi(e)?Xi(n)?t.removeAttributeNS(Ui,qi(e)):t.setAttributeNS(Ui,e,n):zr(t,e,n)}function zr(t,e,n){if(Xi(n))t.removeAttribute(e);else{if(tt&&!et&&"TEXTAREA"===t.tagName&&"placeholder"===e&&""!==n&&!t.__ieph){var i=function(e){e.stopImmediatePropagation(),t.removeEventListener("input",i)};t.addEventListener("input",i),t.__ieph=!0}t.setAttribute(e,n)}}var Hr={create:Rr,update:Rr};function Wr(t,e){var n=e.elm,o=e.data,a=t.data;if(!(i(o.staticClass)&&i(o.class)&&(i(a)||i(a.staticClass)&&i(a.class)))){var s=Gi(e),c=n._transitionClasses;r(c)&&(s=Ji(s,Qi(c))),s!==n._prevClass&&(n.setAttribute("class",s),n._prevClass=s)}}var Ur,Yr={create:Wr,update:Wr},qr="__r",Xr="__c";function Gr(t){if(r(t[qr])){var e=tt?"change":"input";t[e]=[].concat(t[qr],t[e]||[]),delete t[qr]}r(t[Xr])&&(t.change=[].concat(t[Xr],t.change||[]),delete t[Xr])}function Kr(t,e,n){var i=Ur;return function r(){var o=e.apply(null,arguments);null!==o&&Qr(t,r,n,i)}}var Zr=ae&&!(rt&&Number(rt[1])<=53);function Jr(t,e,n,i){if(Zr){var r=qn,o=e;e=o._wrapper=function(t){if(t.target===t.currentTarget||t.timeStamp>=r||t.timeStamp<=0||t.target.ownerDocument!==document)return o.apply(this,arguments)}}Ur.addEventListener(t,e,at?{capture:n,passive:i}:n)}function Qr(t,e,n,i){(i||Ur).removeEventListener(t,e._wrapper||e,n)}function to(t,e){if(!i(t.data.on)||!i(e.data.on)){var n=e.data.on||{},r=t.data.on||{};Ur=e.elm,Gr(n),we(n,r,Jr,Qr,Kr,e.context),Ur=void 0}}var eo,no={create:to,update:to};function io(t,e){if(!i(t.data.domProps)||!i(e.data.domProps)){var n,o,a=e.elm,s=t.data.domProps||{},c=e.data.domProps||{};for(n in r(c.__ob__)&&(c=e.data.domProps=T({},c)),s)n in c||(a[n]="");for(n in c){if(o=c[n],"textContent"===n||"innerHTML"===n){if(e.children&&(e.children.length=0),o===s[n])continue;1===a.childNodes.length&&a.removeChild(a.childNodes[0])}if("value"===n&&"PROGRESS"!==a.tagName){a._value=o;var l=i(o)?"":String(o);ro(a,l)&&(a.value=l)}else if("innerHTML"===n&&rr(a.tagName)&&i(a.innerHTML)){eo=eo||document.createElement("div"),eo.innerHTML=""+o+"";var u=eo.firstChild;while(a.firstChild)a.removeChild(a.firstChild);while(u.firstChild)a.appendChild(u.firstChild)}else if(o!==s[n])try{a[n]=o}catch(_a){}}}}function ro(t,e){return!t.composing&&("OPTION"===t.tagName||oo(t,e)||ao(t,e))}function oo(t,e){var n=!0;try{n=document.activeElement!==t}catch(_a){}return n&&t.value!==e}function ao(t,e){var n=t.value,i=t._vModifiers;if(r(i)){if(i.number)return v(n)!==v(e);if(i.trim)return n.trim()!==e.trim()}return n!==e}var so={create:io,update:io},co=x((function(t){var e={},n=/;(?![^(]*\))/g,i=/:(.+)/;return t.split(n).forEach((function(t){if(t){var n=t.split(i);n.length>1&&(e[n[0].trim()]=n[1].trim())}})),e}));function lo(t){var e=uo(t.style);return t.staticStyle?T(t.staticStyle,e):e}function uo(t){return Array.isArray(t)?I(t):"string"===typeof t?co(t):t}function ho(t,e){var n,i={};if(e){var r=t;while(r.componentInstance)r=r.componentInstance._vnode,r&&r.data&&(n=lo(r.data))&&T(i,n)}(n=lo(t.data))&&T(i,n);var o=t;while(o=o.parent)o.data&&(n=lo(o.data))&&T(i,n);return i}var fo,po=/^--/,vo=/\s*!important$/,mo=function(t,e,n){if(po.test(e))t.style.setProperty(e,n);else if(vo.test(n))t.style.setProperty(k(e),n.replace(vo,""),"important");else{var i=bo(e);if(Array.isArray(n))for(var r=0,o=n.length;r-1?e.split(xo).forEach((function(e){return t.classList.add(e)})):t.classList.add(e);else{var n=" "+(t.getAttribute("class")||"")+" ";n.indexOf(" "+e+" ")<0&&t.setAttribute("class",(n+e).trim())}}function _o(t,e){if(e&&(e=e.trim()))if(t.classList)e.indexOf(" ")>-1?e.split(xo).forEach((function(e){return t.classList.remove(e)})):t.classList.remove(e),t.classList.length||t.removeAttribute("class");else{var n=" "+(t.getAttribute("class")||"")+" ",i=" "+e+" ";while(n.indexOf(i)>=0)n=n.replace(i," ");n=n.trim(),n?t.setAttribute("class",n):t.removeAttribute("class")}}function So(t){if(t){if("object"===typeof t){var e={};return!1!==t.css&&T(e,Co(t.name||"v")),T(e,t),e}return"string"===typeof t?Co(t):void 0}}var Co=x((function(t){return{enterClass:t+"-enter",enterToClass:t+"-enter-to",enterActiveClass:t+"-enter-active",leaveClass:t+"-leave",leaveToClass:t+"-leave-to",leaveActiveClass:t+"-leave-active"}})),ko=K&&!et,jo="transition",Ao="animation",$o="transition",Eo="transitionend",To="animation",Io="animationend";ko&&(void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend&&($o="WebkitTransition",Eo="webkitTransitionEnd"),void 0===window.onanimationend&&void 0!==window.onwebkitanimationend&&(To="WebkitAnimation",Io="webkitAnimationEnd"));var Lo=K?window.requestAnimationFrame?window.requestAnimationFrame.bind(window):setTimeout:function(t){return t()};function Mo(t){Lo((function(){Lo(t)}))}function Do(t,e){var n=t._transitionClasses||(t._transitionClasses=[]);n.indexOf(e)<0&&(n.push(e),Oo(t,e))}function Bo(t,e){t._transitionClasses&&b(t._transitionClasses,e),_o(t,e)}function Po(t,e,n){var i=Vo(t,e),r=i.type,o=i.timeout,a=i.propCount;if(!r)return n();var s=r===jo?Eo:Io,c=0,l=function(){t.removeEventListener(s,u),n()},u=function(e){e.target===t&&++c>=a&&l()};setTimeout((function(){c0&&(n=jo,u=a,h=o.length):e===Ao?l>0&&(n=Ao,u=l,h=c.length):(u=Math.max(a,l),n=u>0?a>l?jo:Ao:null,h=n?n===jo?o.length:c.length:0);var f=n===jo&&No.test(i[$o+"Property"]);return{type:n,timeout:u,propCount:h,hasTransform:f}}function Ro(t,e){while(t.length1}function Yo(t,e){!0!==e.data.show&&zo(e)}var qo=K?{create:Yo,activate:Yo,remove:function(t,e){!0!==t.data.show?Ho(t,e):e()}}:{},Xo=[Hr,Yr,no,so,wo,qo],Go=Xo.concat(Vr),Ko=Tr({nodeOps:_r,modules:Go});et&&document.addEventListener("selectionchange",(function(){var t=document.activeElement;t&&t.vmodel&&ra(t,"input")}));var Zo={inserted:function(t,e,n,i){"select"===n.tag?(i.elm&&!i.elm._vOptions?xe(n,"postpatch",(function(){Zo.componentUpdated(t,e,n)})):Jo(t,e,n.context),t._vOptions=[].map.call(t.options,ea)):("textarea"===n.tag||lr(t.type))&&(t._vModifiers=e.modifiers,e.modifiers.lazy||(t.addEventListener("compositionstart",na),t.addEventListener("compositionend",ia),t.addEventListener("change",ia),et&&(t.vmodel=!0)))},componentUpdated:function(t,e,n){if("select"===n.tag){Jo(t,e,n.context);var i=t._vOptions,r=t._vOptions=[].map.call(t.options,ea);if(r.some((function(t,e){return!B(t,i[e])}))){var o=t.multiple?e.value.some((function(t){return ta(t,r)})):e.value!==e.oldValue&&ta(e.value,r);o&&ra(t,"change")}}}};function Jo(t,e,n){Qo(t,e,n),(tt||nt)&&setTimeout((function(){Qo(t,e,n)}),0)}function Qo(t,e,n){var i=e.value,r=t.multiple;if(!r||Array.isArray(i)){for(var o,a,s=0,c=t.options.length;s-1,a.selected!==o&&(a.selected=o);else if(B(ea(a),i))return void(t.selectedIndex!==s&&(t.selectedIndex=s));r||(t.selectedIndex=-1)}}function ta(t,e){return e.every((function(e){return!B(e,t)}))}function ea(t){return"_value"in t?t._value:t.value}function na(t){t.target.composing=!0}function ia(t){t.target.composing&&(t.target.composing=!1,ra(t.target,"input"))}function ra(t,e){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0),t.dispatchEvent(n)}function oa(t){return!t.componentInstance||t.data&&t.data.transition?t:oa(t.componentInstance._vnode)}var aa={bind:function(t,e,n){var i=e.value;n=oa(n);var r=n.data&&n.data.transition,o=t.__vOriginalDisplay="none"===t.style.display?"":t.style.display;i&&r?(n.data.show=!0,zo(n,(function(){t.style.display=o}))):t.style.display=i?o:"none"},update:function(t,e,n){var i=e.value,r=e.oldValue;if(!i!==!r){n=oa(n);var o=n.data&&n.data.transition;o?(n.data.show=!0,i?zo(n,(function(){t.style.display=t.__vOriginalDisplay})):Ho(n,(function(){t.style.display="none"}))):t.style.display=i?t.__vOriginalDisplay:"none"}},unbind:function(t,e,n,i,r){r||(t.style.display=t.__vOriginalDisplay)}},sa={model:Zo,show:aa},ca={name:String,appear:Boolean,css:Boolean,mode:String,type:String,enterClass:String,leaveClass:String,enterToClass:String,leaveToClass:String,enterActiveClass:String,leaveActiveClass:String,appearClass:String,appearActiveClass:String,appearToClass:String,duration:[Number,String,Object]};function la(t){var e=t&&t.componentOptions;return e&&e.Ctor.options.abstract?la(_n(e.children)):t}function ua(t){var e={},n=t.$options;for(var i in n.propsData)e[i]=t[i];var r=n._parentListeners;for(var o in r)e[_(o)]=r[o];return e}function ha(t,e){if(/\d-keep-alive$/.test(e.tag))return t("keep-alive",{props:e.componentOptions.propsData})}function fa(t){while(t=t.parent)if(t.data.transition)return!0}function da(t,e){return e.key===t.key&&e.tag===t.tag}var pa=function(t){return t.tag||On(t)},va=function(t){return"show"===t.name},ma={name:"transition",props:ca,abstract:!0,render:function(t){var e=this,n=this.$slots.default;if(n&&(n=n.filter(pa),n.length)){0;var i=this.mode;0;var r=n[0];if(fa(this.$vnode))return r;var o=la(r);if(!o)return r;if(this._leaving)return ha(t,r);var a="__transition-"+this._uid+"-";o.key=null==o.key?o.isComment?a+"comment":a+o.tag:s(o.key)?0===String(o.key).indexOf(a)?o.key:a+o.key:o.key;var c=(o.data||(o.data={})).transition=ua(this),l=this._vnode,u=la(l);if(o.data.directives&&o.data.directives.some(va)&&(o.data.show=!0),u&&u.data&&!da(o,u)&&!On(u)&&(!u.componentInstance||!u.componentInstance._vnode.isComment)){var h=u.data.transition=T({},c);if("out-in"===i)return this._leaving=!0,xe(h,"afterLeave",(function(){e._leaving=!1,e.$forceUpdate()})),ha(t,r);if("in-out"===i){if(On(o))return l;var f,d=function(){f()};xe(c,"afterEnter",d),xe(c,"enterCancelled",d),xe(h,"delayLeave",(function(t){f=t}))}}return r}}},ga=T({tag:String,moveClass:String},ca);delete ga.mode;var ba={props:ga,beforeMount:function(){var t=this,e=this._update;this._update=function(n,i){var r=Tn(t);t.__patch__(t._vnode,t.kept,!1,!0),t._vnode=t.kept,r(),e.call(t,n,i)}},render:function(t){for(var e=this.tag||this.$vnode.data.tag||"span",n=Object.create(null),i=this.prevChildren=this.children,r=this.$slots.default||[],o=this.children=[],a=ua(this),s=0;s4)return t;for(n=[],i=0;i1&&"0"==r.charAt(0)&&(o=L.test(r)?16:8,r=r.slice(8==o?1:2)),""===r)a=0;else{if(!(10==o?D:8==o?M:B).test(r))return t;a=parseInt(r,o)}n.push(a)}for(i=0;i=C(256,5-e))return null}else if(a>255)return null;for(s=n.pop(),i=0;i6)return;i=0;while(f()){if(r=null,i>0){if(!("."==f()&&i<4))return;h++}if(!I.test(f()))return;while(I.test(f())){if(o=parseInt(f(),10),null===r)r=o;else{if(0==r)return;r=10*r+o}if(r>255)return;h++}c[l]=256*c[l]+r,i++,2!=i&&4!=i||l++}if(4!=i)return;break}if(":"==f()){if(h++,!f())return}else if(f())return;c[l++]=e}else{if(null!==u)return;h++,l++,u=l}}if(null!==u){a=l-u,l=7;while(0!=l&&a>0)s=c[l],c[l--]=c[u+a-1],c[u+--a]=s}else if(8!=l)return;return c},W=function(t){for(var e=null,n=1,i=null,r=0,o=0;o<8;o++)0!==t[o]?(r>n&&(e=i,n=r),i=null,r=0):(null===i&&(i=o),++r);return r>n&&(e=i,n=r),e},U=function(t){var e,n,i,r;if("number"==typeof t){for(e=[],n=0;n<4;n++)e.unshift(t%256),t=S(t/256);return e.join(".")}if("object"==typeof t){for(e="",i=W(t),n=0;n<8;n++)r&&0===t[n]||(r&&(r=!1),i===n?(e+=n?":":"::",r=!0):(e+=t[n].toString(16),n<7&&(e+=":")));return"["+e+"]"}return t},Y={},q=f({},Y,{" ":1,'"':1,"<":1,">":1,"`":1}),X=f({},q,{"#":1,"?":1,"{":1,"}":1}),G=f({},X,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),K=function(t,e){var n=p(t,0);return n>32&&n<127&&!h(e,t)?t:encodeURIComponent(t)},Z={ftp:21,file:null,http:80,https:443,ws:80,wss:443},J=function(t){return h(Z,t.scheme)},Q=function(t){return""!=t.username||""!=t.password},tt=function(t){return!t.host||t.cannotBeABaseURL||"file"==t.scheme},et=function(t,e){var n;return 2==t.length&&E.test(t.charAt(0))&&(":"==(n=t.charAt(1))||!e&&"|"==n)},nt=function(t){var e;return t.length>1&&et(t.slice(0,2))&&(2==t.length||"/"===(e=t.charAt(2))||"\\"===e||"?"===e||"#"===e)},it=function(t){var e=t.path,n=e.length;!n||"file"==t.scheme&&1==n&&et(e[0],!0)||e.pop()},rt=function(t){return"."===t||"%2e"===t.toLowerCase()},ot=function(t){return t=t.toLowerCase(),".."===t||"%2e."===t||".%2e"===t||"%2e%2e"===t},at={},st={},ct={},lt={},ut={},ht={},ft={},dt={},pt={},vt={},mt={},gt={},bt={},yt={},wt={},xt={},Ot={},_t={},St={},Ct={},kt={},jt=function(t,e,n,r){var o,a,s,c,l=n||at,u=0,f="",p=!1,v=!1,m=!1;n||(t.scheme="",t.username="",t.password="",t.host=null,t.port=null,t.path=[],t.query=null,t.fragment=null,t.cannotBeABaseURL=!1,e=e.replace(V,"")),e=e.replace(R,""),o=d(e);while(u<=o.length){switch(a=o[u],l){case at:if(!a||!E.test(a)){if(n)return j;l=ct;continue}f+=a.toLowerCase(),l=st;break;case st:if(a&&(T.test(a)||"+"==a||"-"==a||"."==a))f+=a.toLowerCase();else{if(":"!=a){if(n)return j;f="",l=ct,u=0;continue}if(n&&(J(t)!=h(Z,f)||"file"==f&&(Q(t)||null!==t.port)||"file"==t.scheme&&!t.host))return;if(t.scheme=f,n)return void(J(t)&&Z[t.scheme]==t.port&&(t.port=null));f="","file"==t.scheme?l=yt:J(t)&&r&&r.scheme==t.scheme?l=lt:J(t)?l=dt:"/"==o[u+1]?(l=ut,u++):(t.cannotBeABaseURL=!0,t.path.push(""),l=St)}break;case ct:if(!r||r.cannotBeABaseURL&&"#"!=a)return j;if(r.cannotBeABaseURL&&"#"==a){t.scheme=r.scheme,t.path=r.path.slice(),t.query=r.query,t.fragment="",t.cannotBeABaseURL=!0,l=kt;break}l="file"==r.scheme?yt:ht;continue;case lt:if("/"!=a||"/"!=o[u+1]){l=ht;continue}l=pt,u++;break;case ut:if("/"==a){l=vt;break}l=_t;continue;case ht:if(t.scheme=r.scheme,a==i)t.username=r.username,t.password=r.password,t.host=r.host,t.port=r.port,t.path=r.path.slice(),t.query=r.query;else if("/"==a||"\\"==a&&J(t))l=ft;else if("?"==a)t.username=r.username,t.password=r.password,t.host=r.host,t.port=r.port,t.path=r.path.slice(),t.query="",l=Ct;else{if("#"!=a){t.username=r.username,t.password=r.password,t.host=r.host,t.port=r.port,t.path=r.path.slice(),t.path.pop(),l=_t;continue}t.username=r.username,t.password=r.password,t.host=r.host,t.port=r.port,t.path=r.path.slice(),t.query=r.query,t.fragment="",l=kt}break;case ft:if(!J(t)||"/"!=a&&"\\"!=a){if("/"!=a){t.username=r.username,t.password=r.password,t.host=r.host,t.port=r.port,l=_t;continue}l=vt}else l=pt;break;case dt:if(l=pt,"/"!=a||"/"!=f.charAt(u+1))continue;u++;break;case pt:if("/"!=a&&"\\"!=a){l=vt;continue}break;case vt:if("@"==a){p&&(f="%40"+f),p=!0,s=d(f);for(var g=0;g65535)return $;t.port=J(t)&&w===Z[t.scheme]?null:w,f=""}if(n)return;l=Ot;continue}return $}f+=a;break;case yt:if(t.scheme="file","/"==a||"\\"==a)l=wt;else{if(!r||"file"!=r.scheme){l=_t;continue}if(a==i)t.host=r.host,t.path=r.path.slice(),t.query=r.query;else if("?"==a)t.host=r.host,t.path=r.path.slice(),t.query="",l=Ct;else{if("#"!=a){nt(o.slice(u).join(""))||(t.host=r.host,t.path=r.path.slice(),it(t)),l=_t;continue}t.host=r.host,t.path=r.path.slice(),t.query=r.query,t.fragment="",l=kt}}break;case wt:if("/"==a||"\\"==a){l=xt;break}r&&"file"==r.scheme&&!nt(o.slice(u).join(""))&&(et(r.path[0],!0)?t.path.push(r.path[0]):t.host=r.host),l=_t;continue;case xt:if(a==i||"/"==a||"\\"==a||"?"==a||"#"==a){if(!n&&et(f))l=_t;else if(""==f){if(t.host="",n)return;l=Ot}else{if(c=F(t,f),c)return c;if("localhost"==t.host&&(t.host=""),n)return;f="",l=Ot}continue}f+=a;break;case Ot:if(J(t)){if(l=_t,"/"!=a&&"\\"!=a)continue}else if(n||"?"!=a)if(n||"#"!=a){if(a!=i&&(l=_t,"/"!=a))continue}else t.fragment="",l=kt;else t.query="",l=Ct;break;case _t:if(a==i||"/"==a||"\\"==a&&J(t)||!n&&("?"==a||"#"==a)){if(ot(f)?(it(t),"/"==a||"\\"==a&&J(t)||t.path.push("")):rt(f)?"/"==a||"\\"==a&&J(t)||t.path.push(""):("file"==t.scheme&&!t.path.length&&et(f)&&(t.host&&(t.host=""),f=f.charAt(0)+":"),t.path.push(f)),f="","file"==t.scheme&&(a==i||"?"==a||"#"==a))while(t.path.length>1&&""===t.path[0])t.path.shift();"?"==a?(t.query="",l=Ct):"#"==a&&(t.fragment="",l=kt)}else f+=K(a,X);break;case St:"?"==a?(t.query="",l=Ct):"#"==a?(t.fragment="",l=kt):a!=i&&(t.path[0]+=K(a,Y));break;case Ct:n||"#"!=a?a!=i&&("'"==a&&J(t)?t.query+="%27":t.query+="#"==a?"%23":K(a,Y)):(t.fragment="",l=kt);break;case kt:a!=i&&(t.fragment+=K(a,q));break}u++}},At=function(t){var e,n,i=u(this,At,"URL"),r=arguments.length>1?arguments[1]:void 0,a=String(t),s=O(i,{type:"URL"});if(void 0!==r)if(r instanceof At)e=_(r);else if(n=jt(e={},String(r)),n)throw TypeError(n);if(n=jt(s,a,null,e),n)throw TypeError(n);var c=s.searchParams=new w,l=x(c);l.updateSearchParams(s.query),l.updateURL=function(){s.query=String(c)||null},o||(i.href=Et.call(i),i.origin=Tt.call(i),i.protocol=It.call(i),i.username=Lt.call(i),i.password=Mt.call(i),i.host=Dt.call(i),i.hostname=Bt.call(i),i.port=Pt.call(i),i.pathname=Nt.call(i),i.search=Vt.call(i),i.searchParams=Rt.call(i),i.hash=Ft.call(i))},$t=At.prototype,Et=function(){var t=_(this),e=t.scheme,n=t.username,i=t.password,r=t.host,o=t.port,a=t.path,s=t.query,c=t.fragment,l=e+":";return null!==r?(l+="//",Q(t)&&(l+=n+(i?":"+i:"")+"@"),l+=U(r),null!==o&&(l+=":"+o)):"file"==e&&(l+="//"),l+=t.cannotBeABaseURL?a[0]:a.length?"/"+a.join("/"):"",null!==s&&(l+="?"+s),null!==c&&(l+="#"+c),l},Tt=function(){var t=_(this),e=t.scheme,n=t.port;if("blob"==e)try{return new URL(e.path[0]).origin}catch(i){return"null"}return"file"!=e&&J(t)?e+"://"+U(t.host)+(null!==n?":"+n:""):"null"},It=function(){return _(this).scheme+":"},Lt=function(){return _(this).username},Mt=function(){return _(this).password},Dt=function(){var t=_(this),e=t.host,n=t.port;return null===e?"":null===n?U(e):U(e)+":"+n},Bt=function(){var t=_(this).host;return null===t?"":U(t)},Pt=function(){var t=_(this).port;return null===t?"":String(t)},Nt=function(){var t=_(this),e=t.path;return t.cannotBeABaseURL?e[0]:e.length?"/"+e.join("/"):""},Vt=function(){var t=_(this).query;return t?"?"+t:""},Rt=function(){return _(this).searchParams},Ft=function(){var t=_(this).fragment;return t?"#"+t:""},zt=function(t,e){return{get:t,set:e,configurable:!0,enumerable:!0}};if(o&&c($t,{href:zt(Et,(function(t){var e=_(this),n=String(t),i=jt(e,n);if(i)throw TypeError(i);x(e.searchParams).updateSearchParams(e.query)})),origin:zt(Tt),protocol:zt(It,(function(t){var e=_(this);jt(e,String(t)+":",at)})),username:zt(Lt,(function(t){var e=_(this),n=d(String(t));if(!tt(e)){e.username="";for(var i=0;i1?arguments[1]:void 0,e.length)),i=String(t);return u?u.call(e,i,n):e.slice(n,n+i.length)===i}})},"2cf4":function(t,e,n){var i,r,o,a=n("da84"),s=n("d039"),c=n("c6b6"),l=n("0366"),u=n("1be4"),h=n("cc12"),f=n("1cdc"),d=a.location,p=a.setImmediate,v=a.clearImmediate,m=a.process,g=a.MessageChannel,b=a.Dispatch,y=0,w={},x="onreadystatechange",O=function(t){if(w.hasOwnProperty(t)){var e=w[t];delete w[t],e()}},_=function(t){return function(){O(t)}},S=function(t){O(t.data)},C=function(t){a.postMessage(t+"",d.protocol+"//"+d.host)};p&&v||(p=function(t){var e=[],n=1;while(arguments.length>n)e.push(arguments[n++]);return w[++y]=function(){("function"==typeof t?t:Function(t)).apply(void 0,e)},i(y),y},v=function(t){delete w[t]},"process"==c(m)?i=function(t){m.nextTick(_(t))}:b&&b.now?i=function(t){b.now(_(t))}:g&&!f?(r=new g,o=r.port2,r.port1.onmessage=S,i=l(o.postMessage,o,1)):!a.addEventListener||"function"!=typeof postMessage||a.importScripts||s(C)||"file:"===d.protocol?i=x in h("script")?function(t){u.appendChild(h("script"))[x]=function(){u.removeChild(this),O(t)}}:function(t){setTimeout(_(t),0)}:(i=C,a.addEventListener("message",S,!1))),t.exports={set:p,clear:v}},"2d00":function(t,e,n){var i,r,o=n("da84"),a=n("342f"),s=o.process,c=s&&s.versions,l=c&&c.v8;l?(i=l.split("."),r=i[0]+i[1]):a&&(i=a.match(/Edge\/(\d+)/),(!i||i[1]>=74)&&(i=a.match(/Chrome\/(\d+)/),i&&(r=i[1]))),t.exports=r&&+r},"2f62":function(t,e,n){"use strict";(function(t){ +/*! + * vuex v3.5.1 + * (c) 2020 Evan You + * @license MIT + */ +function n(t){var e=Number(t.version.split(".")[0]);if(e>=2)t.mixin({beforeCreate:i});else{var n=t.prototype._init;t.prototype._init=function(t){void 0===t&&(t={}),t.init=t.init?[i].concat(t.init):i,n.call(this,t)}}function i(){var t=this.$options;t.store?this.$store="function"===typeof t.store?t.store():t.store:t.parent&&t.parent.$store&&(this.$store=t.parent.$store)}}var i="undefined"!==typeof window?window:"undefined"!==typeof t?t:{},r=i.__VUE_DEVTOOLS_GLOBAL_HOOK__;function o(t){r&&(t._devtoolHook=r,r.emit("vuex:init",t),r.on("vuex:travel-to-state",(function(e){t.replaceState(e)})),t.subscribe((function(t,e){r.emit("vuex:mutation",t,e)}),{prepend:!0}),t.subscribeAction((function(t,e){r.emit("vuex:action",t,e)}),{prepend:!0}))}function a(t,e){return t.filter(e)[0]}function s(t,e){if(void 0===e&&(e=[]),null===t||"object"!==typeof t)return t;var n=a(e,(function(e){return e.original===t}));if(n)return n.copy;var i=Array.isArray(t)?[]:{};return e.push({original:t,copy:i}),Object.keys(t).forEach((function(n){i[n]=s(t[n],e)})),i}function c(t,e){Object.keys(t).forEach((function(n){return e(t[n],n)}))}function l(t){return null!==t&&"object"===typeof t}function u(t){return t&&"function"===typeof t.then}function h(t,e){return function(){return t(e)}}var f=function(t,e){this.runtime=e,this._children=Object.create(null),this._rawModule=t;var n=t.state;this.state=("function"===typeof n?n():n)||{}},d={namespaced:{configurable:!0}};d.namespaced.get=function(){return!!this._rawModule.namespaced},f.prototype.addChild=function(t,e){this._children[t]=e},f.prototype.removeChild=function(t){delete this._children[t]},f.prototype.getChild=function(t){return this._children[t]},f.prototype.hasChild=function(t){return t in this._children},f.prototype.update=function(t){this._rawModule.namespaced=t.namespaced,t.actions&&(this._rawModule.actions=t.actions),t.mutations&&(this._rawModule.mutations=t.mutations),t.getters&&(this._rawModule.getters=t.getters)},f.prototype.forEachChild=function(t){c(this._children,t)},f.prototype.forEachGetter=function(t){this._rawModule.getters&&c(this._rawModule.getters,t)},f.prototype.forEachAction=function(t){this._rawModule.actions&&c(this._rawModule.actions,t)},f.prototype.forEachMutation=function(t){this._rawModule.mutations&&c(this._rawModule.mutations,t)},Object.defineProperties(f.prototype,d);var p=function(t){this.register([],t,!1)};function v(t,e,n){if(e.update(n),n.modules)for(var i in n.modules){if(!e.getChild(i))return void 0;v(t.concat(i),e.getChild(i),n.modules[i])}}p.prototype.get=function(t){return t.reduce((function(t,e){return t.getChild(e)}),this.root)},p.prototype.getNamespace=function(t){var e=this.root;return t.reduce((function(t,n){return e=e.getChild(n),t+(e.namespaced?n+"/":"")}),"")},p.prototype.update=function(t){v([],this.root,t)},p.prototype.register=function(t,e,n){var i=this;void 0===n&&(n=!0);var r=new f(e,n);if(0===t.length)this.root=r;else{var o=this.get(t.slice(0,-1));o.addChild(t[t.length-1],r)}e.modules&&c(e.modules,(function(e,r){i.register(t.concat(r),e,n)}))},p.prototype.unregister=function(t){var e=this.get(t.slice(0,-1)),n=t[t.length-1],i=e.getChild(n);i&&i.runtime&&e.removeChild(n)},p.prototype.isRegistered=function(t){var e=this.get(t.slice(0,-1)),n=t[t.length-1];return e.hasChild(n)};var m;var g=function(t){var e=this;void 0===t&&(t={}),!m&&"undefined"!==typeof window&&window.Vue&&T(window.Vue);var n=t.plugins;void 0===n&&(n=[]);var i=t.strict;void 0===i&&(i=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new p(t),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new m,this._makeLocalGettersCache=Object.create(null);var r=this,a=this,s=a.dispatch,c=a.commit;this.dispatch=function(t,e){return s.call(r,t,e)},this.commit=function(t,e,n){return c.call(r,t,e,n)},this.strict=i;var l=this._modules.root.state;O(this,l,[],this._modules.root),x(this,l),n.forEach((function(t){return t(e)}));var u=void 0!==t.devtools?t.devtools:m.config.devtools;u&&o(this)},b={state:{configurable:!0}};function y(t,e,n){return e.indexOf(t)<0&&(n&&n.prepend?e.unshift(t):e.push(t)),function(){var n=e.indexOf(t);n>-1&&e.splice(n,1)}}function w(t,e){t._actions=Object.create(null),t._mutations=Object.create(null),t._wrappedGetters=Object.create(null),t._modulesNamespaceMap=Object.create(null);var n=t.state;O(t,n,[],t._modules.root,!0),x(t,n,e)}function x(t,e,n){var i=t._vm;t.getters={},t._makeLocalGettersCache=Object.create(null);var r=t._wrappedGetters,o={};c(r,(function(e,n){o[n]=h(e,t),Object.defineProperty(t.getters,n,{get:function(){return t._vm[n]},enumerable:!0})}));var a=m.config.silent;m.config.silent=!0,t._vm=new m({data:{$$state:e},computed:o}),m.config.silent=a,t.strict&&A(t),i&&(n&&t._withCommit((function(){i._data.$$state=null})),m.nextTick((function(){return i.$destroy()})))}function O(t,e,n,i,r){var o=!n.length,a=t._modules.getNamespace(n);if(i.namespaced&&(t._modulesNamespaceMap[a],t._modulesNamespaceMap[a]=i),!o&&!r){var s=$(e,n.slice(0,-1)),c=n[n.length-1];t._withCommit((function(){m.set(s,c,i.state)}))}var l=i.context=_(t,a,n);i.forEachMutation((function(e,n){var i=a+n;C(t,i,e,l)})),i.forEachAction((function(e,n){var i=e.root?n:a+n,r=e.handler||e;k(t,i,r,l)})),i.forEachGetter((function(e,n){var i=a+n;j(t,i,e,l)})),i.forEachChild((function(i,o){O(t,e,n.concat(o),i,r)}))}function _(t,e,n){var i=""===e,r={dispatch:i?t.dispatch:function(n,i,r){var o=E(n,i,r),a=o.payload,s=o.options,c=o.type;return s&&s.root||(c=e+c),t.dispatch(c,a)},commit:i?t.commit:function(n,i,r){var o=E(n,i,r),a=o.payload,s=o.options,c=o.type;s&&s.root||(c=e+c),t.commit(c,a,s)}};return Object.defineProperties(r,{getters:{get:i?function(){return t.getters}:function(){return S(t,e)}},state:{get:function(){return $(t.state,n)}}}),r}function S(t,e){if(!t._makeLocalGettersCache[e]){var n={},i=e.length;Object.keys(t.getters).forEach((function(r){if(r.slice(0,i)===e){var o=r.slice(i);Object.defineProperty(n,o,{get:function(){return t.getters[r]},enumerable:!0})}})),t._makeLocalGettersCache[e]=n}return t._makeLocalGettersCache[e]}function C(t,e,n,i){var r=t._mutations[e]||(t._mutations[e]=[]);r.push((function(e){n.call(t,i.state,e)}))}function k(t,e,n,i){var r=t._actions[e]||(t._actions[e]=[]);r.push((function(e){var r=n.call(t,{dispatch:i.dispatch,commit:i.commit,getters:i.getters,state:i.state,rootGetters:t.getters,rootState:t.state},e);return u(r)||(r=Promise.resolve(r)),t._devtoolHook?r.catch((function(e){throw t._devtoolHook.emit("vuex:error",e),e})):r}))}function j(t,e,n,i){t._wrappedGetters[e]||(t._wrappedGetters[e]=function(t){return n(i.state,i.getters,t.state,t.getters)})}function A(t){t._vm.$watch((function(){return this._data.$$state}),(function(){0}),{deep:!0,sync:!0})}function $(t,e){return e.reduce((function(t,e){return t[e]}),t)}function E(t,e,n){return l(t)&&t.type&&(n=e,e=t,t=t.type),{type:t,payload:e,options:n}}function T(t){m&&t===m||(m=t,n(m))}b.state.get=function(){return this._vm._data.$$state},b.state.set=function(t){0},g.prototype.commit=function(t,e,n){var i=this,r=E(t,e,n),o=r.type,a=r.payload,s=(r.options,{type:o,payload:a}),c=this._mutations[o];c&&(this._withCommit((function(){c.forEach((function(t){t(a)}))})),this._subscribers.slice().forEach((function(t){return t(s,i.state)})))},g.prototype.dispatch=function(t,e){var n=this,i=E(t,e),r=i.type,o=i.payload,a={type:r,payload:o},s=this._actions[r];if(s){try{this._actionSubscribers.slice().filter((function(t){return t.before})).forEach((function(t){return t.before(a,n.state)}))}catch(l){0}var c=s.length>1?Promise.all(s.map((function(t){return t(o)}))):s[0](o);return new Promise((function(t,e){c.then((function(e){try{n._actionSubscribers.filter((function(t){return t.after})).forEach((function(t){return t.after(a,n.state)}))}catch(l){0}t(e)}),(function(t){try{n._actionSubscribers.filter((function(t){return t.error})).forEach((function(e){return e.error(a,n.state,t)}))}catch(l){0}e(t)}))}))}},g.prototype.subscribe=function(t,e){return y(t,this._subscribers,e)},g.prototype.subscribeAction=function(t,e){var n="function"===typeof t?{before:t}:t;return y(n,this._actionSubscribers,e)},g.prototype.watch=function(t,e,n){var i=this;return this._watcherVM.$watch((function(){return t(i.state,i.getters)}),e,n)},g.prototype.replaceState=function(t){var e=this;this._withCommit((function(){e._vm._data.$$state=t}))},g.prototype.registerModule=function(t,e,n){void 0===n&&(n={}),"string"===typeof t&&(t=[t]),this._modules.register(t,e),O(this,this.state,t,this._modules.get(t),n.preserveState),x(this,this.state)},g.prototype.unregisterModule=function(t){var e=this;"string"===typeof t&&(t=[t]),this._modules.unregister(t),this._withCommit((function(){var n=$(e.state,t.slice(0,-1));m.delete(n,t[t.length-1])})),w(this)},g.prototype.hasModule=function(t){return"string"===typeof t&&(t=[t]),this._modules.isRegistered(t)},g.prototype.hotUpdate=function(t){this._modules.update(t),w(this,!0)},g.prototype._withCommit=function(t){var e=this._committing;this._committing=!0,t(),this._committing=e},Object.defineProperties(g.prototype,b);var I=V((function(t,e){var n={};return P(e).forEach((function(e){var i=e.key,r=e.val;n[i]=function(){var e=this.$store.state,n=this.$store.getters;if(t){var i=R(this.$store,"mapState",t);if(!i)return;e=i.context.state,n=i.context.getters}return"function"===typeof r?r.call(this,e,n):e[r]},n[i].vuex=!0})),n})),L=V((function(t,e){var n={};return P(e).forEach((function(e){var i=e.key,r=e.val;n[i]=function(){var e=[],n=arguments.length;while(n--)e[n]=arguments[n];var i=this.$store.commit;if(t){var o=R(this.$store,"mapMutations",t);if(!o)return;i=o.context.commit}return"function"===typeof r?r.apply(this,[i].concat(e)):i.apply(this.$store,[r].concat(e))}})),n})),M=V((function(t,e){var n={};return P(e).forEach((function(e){var i=e.key,r=e.val;r=t+r,n[i]=function(){if(!t||R(this.$store,"mapGetters",t))return this.$store.getters[r]},n[i].vuex=!0})),n})),D=V((function(t,e){var n={};return P(e).forEach((function(e){var i=e.key,r=e.val;n[i]=function(){var e=[],n=arguments.length;while(n--)e[n]=arguments[n];var i=this.$store.dispatch;if(t){var o=R(this.$store,"mapActions",t);if(!o)return;i=o.context.dispatch}return"function"===typeof r?r.apply(this,[i].concat(e)):i.apply(this.$store,[r].concat(e))}})),n})),B=function(t){return{mapState:I.bind(null,t),mapGetters:M.bind(null,t),mapMutations:L.bind(null,t),mapActions:D.bind(null,t)}};function P(t){return N(t)?Array.isArray(t)?t.map((function(t){return{key:t,val:t}})):Object.keys(t).map((function(e){return{key:e,val:t[e]}})):[]}function N(t){return Array.isArray(t)||l(t)}function V(t){return function(e,n){return"string"!==typeof e?(n=e,e=""):"/"!==e.charAt(e.length-1)&&(e+="/"),t(e,n)}}function R(t,e,n){var i=t._modulesNamespaceMap[n];return i}function F(t){void 0===t&&(t={});var e=t.collapsed;void 0===e&&(e=!0);var n=t.filter;void 0===n&&(n=function(t,e,n){return!0});var i=t.transformer;void 0===i&&(i=function(t){return t});var r=t.mutationTransformer;void 0===r&&(r=function(t){return t});var o=t.actionFilter;void 0===o&&(o=function(t,e){return!0});var a=t.actionTransformer;void 0===a&&(a=function(t){return t});var c=t.logMutations;void 0===c&&(c=!0);var l=t.logActions;void 0===l&&(l=!0);var u=t.logger;return void 0===u&&(u=console),function(t){var h=s(t.state);"undefined"!==typeof u&&(c&&t.subscribe((function(t,o){var a=s(o);if(n(t,h,a)){var c=W(),l=r(t),f="mutation "+t.type+c;z(u,f,e),u.log("%c prev state","color: #9E9E9E; font-weight: bold",i(h)),u.log("%c mutation","color: #03A9F4; font-weight: bold",l),u.log("%c next state","color: #4CAF50; font-weight: bold",i(a)),H(u)}h=a})),l&&t.subscribeAction((function(t,n){if(o(t,n)){var i=W(),r=a(t),s="action "+t.type+i;z(u,s,e),u.log("%c action","color: #03A9F4; font-weight: bold",r),H(u)}})))}}function z(t,e,n){var i=n?t.groupCollapsed:t.group;try{i.call(t,e)}catch(r){t.log(e)}}function H(t){try{t.groupEnd()}catch(e){t.log("—— log end ——")}}function W(){var t=new Date;return" @ "+Y(t.getHours(),2)+":"+Y(t.getMinutes(),2)+":"+Y(t.getSeconds(),2)+"."+Y(t.getMilliseconds(),3)}function U(t,e){return new Array(e+1).join(t)}function Y(t,e){return U("0",e-t.toString().length)+t}var q={Store:g,install:T,version:"3.5.1",mapState:I,mapMutations:L,mapGetters:M,mapActions:D,createNamespacedHelpers:B,createLogger:F};e["a"]=q}).call(this,n("c8ba"))},"2fa4":function(t,e,n){"use strict";n("20f6");var i=n("80d2");e["a"]=Object(i["h"])("spacer","div","v-spacer")},"310e":function(t,e,n){t.exports=function(t){var e={};function n(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(i,r,function(e){return t[e]}.bind(null,r));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s="fb15")}({"01f9":function(t,e,n){"use strict";var i=n("2d00"),r=n("5ca1"),o=n("2aba"),a=n("32e9"),s=n("84f2"),c=n("41a0"),l=n("7f20"),u=n("38fd"),h=n("2b4c")("iterator"),f=!([].keys&&"next"in[].keys()),d="@@iterator",p="keys",v="values",m=function(){return this};t.exports=function(t,e,n,g,b,y,w){c(n,e,g);var x,O,_,S=function(t){if(!f&&t in A)return A[t];switch(t){case p:return function(){return new n(this,t)};case v:return function(){return new n(this,t)}}return function(){return new n(this,t)}},C=e+" Iterator",k=b==v,j=!1,A=t.prototype,$=A[h]||A[d]||b&&A[b],E=$||S(b),T=b?k?S("entries"):E:void 0,I="Array"==e&&A.entries||$;if(I&&(_=u(I.call(new t)),_!==Object.prototype&&_.next&&(l(_,C,!0),i||"function"==typeof _[h]||a(_,h,m))),k&&$&&$.name!==v&&(j=!0,E=function(){return $.call(this)}),i&&!w||!f&&!j&&A[h]||a(A,h,E),s[e]=E,s[C]=m,b)if(x={values:k?E:S(v),keys:y?E:S(p),entries:T},w)for(O in x)O in A||o(A,O,x[O]);else r(r.P+r.F*(f||j),e,x);return x}},"02f4":function(t,e,n){var i=n("4588"),r=n("be13");t.exports=function(t){return function(e,n){var o,a,s=String(r(e)),c=i(n),l=s.length;return c<0||c>=l?t?"":void 0:(o=s.charCodeAt(c),o<55296||o>56319||c+1===l||(a=s.charCodeAt(c+1))<56320||a>57343?t?s.charAt(c):o:t?s.slice(c,c+2):a-56320+(o-55296<<10)+65536)}}},"0390":function(t,e,n){"use strict";var i=n("02f4")(!0);t.exports=function(t,e,n){return e+(n?i(t,e).length:1)}},"0bfb":function(t,e,n){"use strict";var i=n("cb7c");t.exports=function(){var t=i(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},"0d58":function(t,e,n){var i=n("ce10"),r=n("e11e");t.exports=Object.keys||function(t){return i(t,r)}},1495:function(t,e,n){var i=n("86cc"),r=n("cb7c"),o=n("0d58");t.exports=n("9e1e")?Object.defineProperties:function(t,e){r(t);var n,a=o(e),s=a.length,c=0;while(s>c)i.f(t,n=a[c++],e[n]);return t}},"214f":function(t,e,n){"use strict";n("b0c5");var i=n("2aba"),r=n("32e9"),o=n("79e5"),a=n("be13"),s=n("2b4c"),c=n("520a"),l=s("species"),u=!o((function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")})),h=function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2===n.length&&"a"===n[0]&&"b"===n[1]}();t.exports=function(t,e,n){var f=s(t),d=!o((function(){var e={};return e[f]=function(){return 7},7!=""[t](e)})),p=d?!o((function(){var e=!1,n=/a/;return n.exec=function(){return e=!0,null},"split"===t&&(n.constructor={},n.constructor[l]=function(){return n}),n[f](""),!e})):void 0;if(!d||!p||"replace"===t&&!u||"split"===t&&!h){var v=/./[f],m=n(a,f,""[t],(function(t,e,n,i,r){return e.exec===c?d&&!r?{done:!0,value:v.call(e,n,i)}:{done:!0,value:t.call(n,e,i)}:{done:!1}})),g=m[0],b=m[1];i(String.prototype,t,g),r(RegExp.prototype,f,2==e?function(t,e){return b.call(t,this,e)}:function(t){return b.call(t,this)})}}},"230e":function(t,e,n){var i=n("d3f4"),r=n("7726").document,o=i(r)&&i(r.createElement);t.exports=function(t){return o?r.createElement(t):{}}},"23c6":function(t,e,n){var i=n("2d95"),r=n("2b4c")("toStringTag"),o="Arguments"==i(function(){return arguments}()),a=function(t,e){try{return t[e]}catch(n){}};t.exports=function(t){var e,n,s;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(n=a(e=Object(t),r))?n:o?i(e):"Object"==(s=i(e))&&"function"==typeof e.callee?"Arguments":s}},2621:function(t,e){e.f=Object.getOwnPropertySymbols},"2aba":function(t,e,n){var i=n("7726"),r=n("32e9"),o=n("69a8"),a=n("ca5a")("src"),s=n("fa5b"),c="toString",l=(""+s).split(c);n("8378").inspectSource=function(t){return s.call(t)},(t.exports=function(t,e,n,s){var c="function"==typeof n;c&&(o(n,"name")||r(n,"name",e)),t[e]!==n&&(c&&(o(n,a)||r(n,a,t[e]?""+t[e]:l.join(String(e)))),t===i?t[e]=n:s?t[e]?t[e]=n:r(t,e,n):(delete t[e],r(t,e,n)))})(Function.prototype,c,(function(){return"function"==typeof this&&this[a]||s.call(this)}))},"2aeb":function(t,e,n){var i=n("cb7c"),r=n("1495"),o=n("e11e"),a=n("613b")("IE_PROTO"),s=function(){},c="prototype",l=function(){var t,e=n("230e")("iframe"),i=o.length,r="<",a=">";e.style.display="none",n("fab2").appendChild(e),e.src="javascript:",t=e.contentWindow.document,t.open(),t.write(r+"script"+a+"document.F=Object"+r+"/script"+a),t.close(),l=t.F;while(i--)delete l[c][o[i]];return l()};t.exports=Object.create||function(t,e){var n;return null!==t?(s[c]=i(t),n=new s,s[c]=null,n[a]=t):n=l(),void 0===e?n:r(n,e)}},"2b4c":function(t,e,n){var i=n("5537")("wks"),r=n("ca5a"),o=n("7726").Symbol,a="function"==typeof o,s=t.exports=function(t){return i[t]||(i[t]=a&&o[t]||(a?o:r)("Symbol."+t))};s.store=i},"2d00":function(t,e){t.exports=!1},"2d95":function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},"2fdb":function(t,e,n){"use strict";var i=n("5ca1"),r=n("d2c8"),o="includes";i(i.P+i.F*n("5147")(o),"String",{includes:function(t){return!!~r(this,t,o).indexOf(t,arguments.length>1?arguments[1]:void 0)}})},"32e9":function(t,e,n){var i=n("86cc"),r=n("4630");t.exports=n("9e1e")?function(t,e,n){return i.f(t,e,r(1,n))}:function(t,e,n){return t[e]=n,t}},"38fd":function(t,e,n){var i=n("69a8"),r=n("4bf8"),o=n("613b")("IE_PROTO"),a=Object.prototype;t.exports=Object.getPrototypeOf||function(t){return t=r(t),i(t,o)?t[o]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?a:null}},"41a0":function(t,e,n){"use strict";var i=n("2aeb"),r=n("4630"),o=n("7f20"),a={};n("32e9")(a,n("2b4c")("iterator"),(function(){return this})),t.exports=function(t,e,n){t.prototype=i(a,{next:r(1,n)}),o(t,e+" Iterator")}},"456d":function(t,e,n){var i=n("4bf8"),r=n("0d58");n("5eda")("keys",(function(){return function(t){return r(i(t))}}))},4588:function(t,e){var n=Math.ceil,i=Math.floor;t.exports=function(t){return isNaN(t=+t)?0:(t>0?i:n)(t)}},4630:function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},"4bf8":function(t,e,n){var i=n("be13");t.exports=function(t){return Object(i(t))}},5147:function(t,e,n){var i=n("2b4c")("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[i]=!1,!"/./"[t](e)}catch(r){}}return!0}},"520a":function(t,e,n){"use strict";var i=n("0bfb"),r=RegExp.prototype.exec,o=String.prototype.replace,a=r,s="lastIndex",c=function(){var t=/a/,e=/b*/g;return r.call(t,"a"),r.call(e,"a"),0!==t[s]||0!==e[s]}(),l=void 0!==/()??/.exec("")[1],u=c||l;u&&(a=function(t){var e,n,a,u,h=this;return l&&(n=new RegExp("^"+h.source+"$(?!\\s)",i.call(h))),c&&(e=h[s]),a=r.call(h,t),c&&a&&(h[s]=h.global?a.index+a[0].length:e),l&&a&&a.length>1&&o.call(a[0],n,(function(){for(u=1;u1?arguments[1]:void 0)}}),n("9c6c")("includes")},6821:function(t,e,n){var i=n("626a"),r=n("be13");t.exports=function(t){return i(r(t))}},"69a8":function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},"6a99":function(t,e,n){var i=n("d3f4");t.exports=function(t,e){if(!i(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!i(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!i(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!i(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")}},7333:function(t,e,n){"use strict";var i=n("9e1e"),r=n("0d58"),o=n("2621"),a=n("52a7"),s=n("4bf8"),c=n("626a"),l=Object.assign;t.exports=!l||n("79e5")((function(){var t={},e={},n=Symbol(),i="abcdefghijklmnopqrst";return t[n]=7,i.split("").forEach((function(t){e[t]=t})),7!=l({},t)[n]||Object.keys(l({},e)).join("")!=i}))?function(t,e){var n=s(t),l=arguments.length,u=1,h=o.f,f=a.f;while(l>u){var d,p=c(arguments[u++]),v=h?r(p).concat(h(p)):r(p),m=v.length,g=0;while(m>g)d=v[g++],i&&!f.call(p,d)||(n[d]=p[d])}return n}:l},7726:function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},"77f1":function(t,e,n){var i=n("4588"),r=Math.max,o=Math.min;t.exports=function(t,e){return t=i(t),t<0?r(t+e,0):o(t,e)}},"79e5":function(t,e){t.exports=function(t){try{return!!t()}catch(e){return!0}}},"7f20":function(t,e,n){var i=n("86cc").f,r=n("69a8"),o=n("2b4c")("toStringTag");t.exports=function(t,e,n){t&&!r(t=n?t:t.prototype,o)&&i(t,o,{configurable:!0,value:e})}},8378:function(t,e){var n=t.exports={version:"2.6.11"};"number"==typeof __e&&(__e=n)},"84f2":function(t,e){t.exports={}},"86cc":function(t,e,n){var i=n("cb7c"),r=n("c69a"),o=n("6a99"),a=Object.defineProperty;e.f=n("9e1e")?Object.defineProperty:function(t,e,n){if(i(t),e=o(e,!0),i(n),r)try{return a(t,e,n)}catch(s){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(t[e]=n.value),t}},"9b43":function(t,e,n){var i=n("d8e8");t.exports=function(t,e,n){if(i(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,i){return t.call(e,n,i)};case 3:return function(n,i,r){return t.call(e,n,i,r)}}return function(){return t.apply(e,arguments)}}},"9c6c":function(t,e,n){var i=n("2b4c")("unscopables"),r=Array.prototype;void 0==r[i]&&n("32e9")(r,i,{}),t.exports=function(t){r[i][t]=!0}},"9def":function(t,e,n){var i=n("4588"),r=Math.min;t.exports=function(t){return t>0?r(i(t),9007199254740991):0}},"9e1e":function(t,e,n){t.exports=!n("79e5")((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a}))},a352:function(t,e){t.exports=n("aa47")},a481:function(t,e,n){"use strict";var i=n("cb7c"),r=n("4bf8"),o=n("9def"),a=n("4588"),s=n("0390"),c=n("5f1b"),l=Math.max,u=Math.min,h=Math.floor,f=/\$([$&`']|\d\d?|<[^>]*>)/g,d=/\$([$&`']|\d\d?)/g,p=function(t){return void 0===t?t:String(t)};n("214f")("replace",2,(function(t,e,n,v){return[function(i,r){var o=t(this),a=void 0==i?void 0:i[e];return void 0!==a?a.call(i,o,r):n.call(String(o),i,r)},function(t,e){var r=v(n,t,this,e);if(r.done)return r.value;var h=i(t),f=String(this),d="function"===typeof e;d||(e=String(e));var g=h.global;if(g){var b=h.unicode;h.lastIndex=0}var y=[];while(1){var w=c(h,f);if(null===w)break;if(y.push(w),!g)break;var x=String(w[0]);""===x&&(h.lastIndex=s(f,o(h.lastIndex),b))}for(var O="",_=0,S=0;S=_&&(O+=f.slice(_,k)+T,_=k+C.length)}return O+f.slice(_)}];function m(t,e,i,o,a,s){var c=i+t.length,l=o.length,u=d;return void 0!==a&&(a=r(a),u=f),n.call(s,u,(function(n,r){var s;switch(r.charAt(0)){case"$":return"$";case"&":return t;case"`":return e.slice(0,i);case"'":return e.slice(c);case"<":s=a[r.slice(1,-1)];break;default:var u=+r;if(0===u)return n;if(u>l){var f=h(u/10);return 0===f?n:f<=l?void 0===o[f-1]?r.charAt(1):o[f-1]+r.charAt(1):n}s=o[u-1]}return void 0===s?"":s}))}}))},aae3:function(t,e,n){var i=n("d3f4"),r=n("2d95"),o=n("2b4c")("match");t.exports=function(t){var e;return i(t)&&(void 0!==(e=t[o])?!!e:"RegExp"==r(t))}},ac6a:function(t,e,n){for(var i=n("cadf"),r=n("0d58"),o=n("2aba"),a=n("7726"),s=n("32e9"),c=n("84f2"),l=n("2b4c"),u=l("iterator"),h=l("toStringTag"),f=c.Array,d={CSSRuleList:!0,CSSStyleDeclaration:!1,CSSValueList:!1,ClientRectList:!1,DOMRectList:!1,DOMStringList:!1,DOMTokenList:!0,DataTransferItemList:!1,FileList:!1,HTMLAllCollection:!1,HTMLCollection:!1,HTMLFormElement:!1,HTMLSelectElement:!1,MediaList:!0,MimeTypeArray:!1,NamedNodeMap:!1,NodeList:!0,PaintRequestList:!1,Plugin:!1,PluginArray:!1,SVGLengthList:!1,SVGNumberList:!1,SVGPathSegList:!1,SVGPointList:!1,SVGStringList:!1,SVGTransformList:!1,SourceBufferList:!1,StyleSheetList:!0,TextTrackCueList:!1,TextTrackList:!1,TouchList:!1},p=r(d),v=0;vu)if(s=c[u++],s!=s)return!0}else for(;l>u;u++)if((t||u in c)&&c[u]===n)return t||u||0;return!t&&-1}}},c649:function(t,e,n){"use strict";(function(t){n.d(e,"c",(function(){return l})),n.d(e,"a",(function(){return s})),n.d(e,"b",(function(){return r})),n.d(e,"d",(function(){return c}));n("a481");function i(){return"undefined"!==typeof window?window.console:t.console}var r=i();function o(t){var e=Object.create(null);return function(n){var i=e[n];return i||(e[n]=t(n))}}var a=/-(\w)/g,s=o((function(t){return t.replace(a,(function(t,e){return e?e.toUpperCase():""}))}));function c(t){null!==t.parentElement&&t.parentElement.removeChild(t)}function l(t,e,n){var i=0===n?t.children[0]:t.children[n-1].nextSibling;t.insertBefore(e,i)}}).call(this,n("c8ba"))},c69a:function(t,e,n){t.exports=!n("9e1e")&&!n("79e5")((function(){return 7!=Object.defineProperty(n("230e")("div"),"a",{get:function(){return 7}}).a}))},c8ba:function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(i){"object"===typeof window&&(n=window)}t.exports=n},ca5a:function(t,e){var n=0,i=Math.random();t.exports=function(t){return"Symbol(".concat(void 0===t?"":t,")_",(++n+i).toString(36))}},cadf:function(t,e,n){"use strict";var i=n("9c6c"),r=n("d53b"),o=n("84f2"),a=n("6821");t.exports=n("01f9")(Array,"Array",(function(t,e){this._t=a(t),this._i=0,this._k=e}),(function(){var t=this._t,e=this._k,n=this._i++;return!t||n>=t.length?(this._t=void 0,r(1)):r(0,"keys"==e?n:"values"==e?t[n]:[n,t[n]])}),"values"),o.Arguments=o.Array,i("keys"),i("values"),i("entries")},cb7c:function(t,e,n){var i=n("d3f4");t.exports=function(t){if(!i(t))throw TypeError(t+" is not an object!");return t}},ce10:function(t,e,n){var i=n("69a8"),r=n("6821"),o=n("c366")(!1),a=n("613b")("IE_PROTO");t.exports=function(t,e){var n,s=r(t),c=0,l=[];for(n in s)n!=a&&i(s,n)&&l.push(n);while(e.length>c)i(s,n=e[c++])&&(~o(l,n)||l.push(n));return l}},d2c8:function(t,e,n){var i=n("aae3"),r=n("be13");t.exports=function(t,e,n){if(i(e))throw TypeError("String#"+n+" doesn't accept regex!");return String(r(t))}},d3f4:function(t,e){t.exports=function(t){return"object"===typeof t?null!==t:"function"===typeof t}},d53b:function(t,e){t.exports=function(t,e){return{value:e,done:!!t}}},d8e8:function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(t+" is not a function!");return t}},e11e:function(t,e){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},f559:function(t,e,n){"use strict";var i=n("5ca1"),r=n("9def"),o=n("d2c8"),a="startsWith",s=""[a];i(i.P+i.F*n("5147")(a),"String",{startsWith:function(t){var e=o(this,t,a),n=r(Math.min(arguments.length>1?arguments[1]:void 0,e.length)),i=String(t);return s?s.call(e,i,n):e.slice(n,n+i.length)===i}})},f6fd:function(t,e){(function(t){var e="currentScript",n=t.getElementsByTagName("script");e in t||Object.defineProperty(t,e,{get:function(){try{throw new Error}catch(i){var t,e=(/.*at [^\(]*\((.*):.+:.+\)$/gi.exec(i.stack)||[!1])[1];for(t in n)if(n[t].src==e||"interactive"==n[t].readyState)return n[t];return null}}})})(document)},f751:function(t,e,n){var i=n("5ca1");i(i.S+i.F,"Object",{assign:n("7333")})},fa5b:function(t,e,n){t.exports=n("5537")("native-function-to-string",Function.toString)},fab2:function(t,e,n){var i=n("7726").document;t.exports=i&&i.documentElement},fb15:function(t,e,n){"use strict";var i;(n.r(e),"undefined"!==typeof window)&&(n("f6fd"),(i=window.document.currentScript)&&(i=i.src.match(/(.+\/)[^/]+\.js(\?.*)?$/))&&(n.p=i[1]));n("f751"),n("f559"),n("ac6a"),n("cadf"),n("456d");function r(t){if(Array.isArray(t))return t}function o(t,e){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(t)){var n=[],i=!0,r=!1,o=void 0;try{for(var a,s=t[Symbol.iterator]();!(i=(a=s.next()).done);i=!0)if(n.push(a.value),e&&n.length===e)break}catch(c){r=!0,o=c}finally{try{i||null==s["return"]||s["return"]()}finally{if(r)throw o}}return n}}function a(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=new Array(e);n=o?r.length:r.indexOf(t)}));return n?a.filter((function(t){return-1!==t})):a}function w(t,e){var n=this;this.$nextTick((function(){return n.$emit(t.toLowerCase(),e)}))}function x(t){var e=this;return function(n){null!==e.realList&&e["onDrag"+t](n),w.call(e,t,n)}}function O(t){return["transition-group","TransitionGroup"].includes(t)}function _(t){if(!t||1!==t.length)return!1;var e=l(t,1),n=e[0].componentOptions;return!!n&&O(n.tag)}function S(t,e,n){return t[n]||(e[n]?e[n]():void 0)}function C(t,e,n){var i=0,r=0,o=S(e,n,"header");o&&(i=o.length,t=t?[].concat(d(o),d(t)):d(o));var a=S(e,n,"footer");return a&&(r=a.length,t=t?[].concat(d(t),d(a)):d(a)),{children:t,headerOffset:i,footerOffset:r}}function k(t,e){var n=null,i=function(t,e){n=g(n,t,e)},r=Object.keys(t).filter((function(t){return"id"===t||t.startsWith("data-")})).reduce((function(e,n){return e[n]=t[n],e}),{});if(i("attrs",r),!e)return n;var o=e.on,a=e.props,s=e.attrs;return i("on",o),i("props",a),Object.assign(n.attrs,s),n}var j=["Start","Add","Remove","Update","End"],A=["Choose","Unchoose","Sort","Filter","Clone"],$=["Move"].concat(j,A).map((function(t){return"on"+t})),E=null,T={options:Object,list:{type:Array,required:!1,default:null},value:{type:Array,required:!1,default:null},noTransitionOnDrag:{type:Boolean,default:!1},clone:{type:Function,default:function(t){return t}},element:{type:String,default:"div"},tag:{type:String,default:null},move:{type:Function,default:null},componentData:{type:Object,required:!1,default:null}},I={name:"draggable",inheritAttrs:!1,props:T,data:function(){return{transitionMode:!1,noneFunctionalComponentMode:!1}},render:function(t){var e=this.$slots.default;this.transitionMode=_(e);var n=C(e,this.$slots,this.$scopedSlots),i=n.children,r=n.headerOffset,o=n.footerOffset;this.headerOffset=r,this.footerOffset=o;var a=k(this.$attrs,this.componentData);return t(this.getTag(),a,i)},created:function(){null!==this.list&&null!==this.value&&m["b"].error("Value and list props are mutually exclusive! Please set one or another."),"div"!==this.element&&m["b"].warn("Element props is deprecated please use tag props instead. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#element-props"),void 0!==this.options&&m["b"].warn("Options props is deprecated, add sortable options directly as vue.draggable item, or use v-bind. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#options-props")},mounted:function(){var t=this;if(this.noneFunctionalComponentMode=this.getTag().toLowerCase()!==this.$el.nodeName.toLowerCase()&&!this.getIsFunctional(),this.noneFunctionalComponentMode&&this.transitionMode)throw new Error("Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ".concat(this.getTag()));var e={};j.forEach((function(n){e["on"+n]=x.call(t,n)})),A.forEach((function(n){e["on"+n]=w.bind(t,n)}));var n=Object.keys(this.$attrs).reduce((function(e,n){return e[Object(m["a"])(n)]=t.$attrs[n],e}),{}),i=Object.assign({},this.options,n,e,{onMove:function(e,n){return t.onDragMove(e,n)}});!("draggable"in i)&&(i.draggable=">*"),this._sortable=new v.a(this.rootContainer,i),this.computeIndexes()},beforeDestroy:function(){void 0!==this._sortable&&this._sortable.destroy()},computed:{rootContainer:function(){return this.transitionMode?this.$el.children[0]:this.$el},realList:function(){return this.list?this.list:this.value}},watch:{options:{handler:function(t){this.updateOptions(t)},deep:!0},$attrs:{handler:function(t){this.updateOptions(t)},deep:!0},realList:function(){this.computeIndexes()}},methods:{getIsFunctional:function(){var t=this._vnode.fnOptions;return t&&t.functional},getTag:function(){return this.tag||this.element},updateOptions:function(t){for(var e in t){var n=Object(m["a"])(e);-1===$.indexOf(n)&&this._sortable.option(n,t[e])}},getChildrenNodes:function(){if(this.noneFunctionalComponentMode)return this.$children[0].$slots.default;var t=this.$slots.default;return this.transitionMode?t[0].child.$slots.default:t},computeIndexes:function(){var t=this;this.$nextTick((function(){t.visibleIndexes=y(t.getChildrenNodes(),t.rootContainer.children,t.transitionMode,t.footerOffset)}))},getUnderlyingVm:function(t){var e=b(this.getChildrenNodes()||[],t);if(-1===e)return null;var n=this.realList[e];return{index:e,element:n}},getUnderlyingPotencialDraggableComponent:function(t){var e=t.__vue__;return e&&e.$options&&O(e.$options._componentTag)?e.$parent:!("realList"in e)&&1===e.$children.length&&"realList"in e.$children[0]?e.$children[0]:e},emitChanges:function(t){var e=this;this.$nextTick((function(){e.$emit("change",t)}))},alterList:function(t){if(this.list)t(this.list);else{var e=d(this.value);t(e),this.$emit("input",e)}},spliceList:function(){var t=arguments,e=function(e){return e.splice.apply(e,d(t))};this.alterList(e)},updatePosition:function(t,e){var n=function(n){return n.splice(e,0,n.splice(t,1)[0])};this.alterList(n)},getRelatedContextFromMoveEvent:function(t){var e=t.to,n=t.related,i=this.getUnderlyingPotencialDraggableComponent(e);if(!i)return{component:i};var r=i.realList,o={list:r,component:i};if(e!==n&&r&&i.getUnderlyingVm){var a=i.getUnderlyingVm(n);if(a)return Object.assign(a,o)}return o},getVmIndex:function(t){var e=this.visibleIndexes,n=e.length;return t>n-1?n:e[t]},getComponent:function(){return this.$slots.default[0].componentInstance},resetTransitionData:function(t){if(this.noTransitionOnDrag&&this.transitionMode){var e=this.getChildrenNodes();e[t].data=null;var n=this.getComponent();n.children=[],n.kept=void 0}},onDragStart:function(t){this.context=this.getUnderlyingVm(t.item),t.item._underlying_vm_=this.clone(this.context.element),E=t.item},onDragAdd:function(t){var e=t.item._underlying_vm_;if(void 0!==e){Object(m["d"])(t.item);var n=this.getVmIndex(t.newIndex);this.spliceList(n,0,e),this.computeIndexes();var i={element:e,newIndex:n};this.emitChanges({added:i})}},onDragRemove:function(t){if(Object(m["c"])(this.rootContainer,t.item,t.oldIndex),"clone"!==t.pullMode){var e=this.context.index;this.spliceList(e,1);var n={element:this.context.element,oldIndex:e};this.resetTransitionData(e),this.emitChanges({removed:n})}else Object(m["d"])(t.clone)},onDragUpdate:function(t){Object(m["d"])(t.item),Object(m["c"])(t.from,t.item,t.oldIndex);var e=this.context.index,n=this.getVmIndex(t.newIndex);this.updatePosition(e,n);var i={element:this.context.element,oldIndex:e,newIndex:n};this.emitChanges({moved:i})},updateProperty:function(t,e){t.hasOwnProperty(e)&&(t[e]+=this.headerOffset)},computeFutureIndex:function(t,e){if(!t.element)return 0;var n=d(e.to.children).filter((function(t){return"none"!==t.style["display"]})),i=n.indexOf(e.related),r=t.component.getVmIndex(i),o=-1!==n.indexOf(E);return o||!e.willInsertAfter?r:r+1},onDragMove:function(t,e){var n=this.move;if(!n||!this.realList)return!0;var i=this.getRelatedContextFromMoveEvent(t),r=this.context,o=this.computeFutureIndex(i,t);Object.assign(r,{futureIndex:o});var a=Object.assign({},t,{relatedContext:i,draggedContext:r});return n(a,e)},onDragEnd:function(){this.computeIndexes(),E=null}}};"undefined"!==typeof window&&"Vue"in window&&window.Vue.component("draggable",I);var L=I;e["default"]=L}})["default"]},3206:function(t,e,n){"use strict";n.d(e,"a",(function(){return s})),n.d(e,"b",(function(){return c}));n("99af");var i=n("ade3"),r=n("2b0e"),o=n("d9bd");function a(t,e){return function(){return Object(o["c"])("The ".concat(t," component must be used inside a ").concat(e))}}function s(t,e,n){var o=e&&n?{register:a(e,n),unregister:a(e,n)}:null;return r["a"].extend({name:"registrable-inject",inject:Object(i["a"])({},t,{default:o})})}function c(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return r["a"].extend({name:"registrable-provide",methods:e?{}:{register:null,unregister:null},provide:function(){return Object(i["a"])({},t,e?this:{register:this.register,unregister:this.unregister})}})}},"326d":function(t,e,n){"use strict";var i=n("e449");e["a"]=i["a"]},3408:function(t,e,n){},3410:function(t,e,n){var i=n("23e7"),r=n("d039"),o=n("7b0b"),a=n("e163"),s=n("e177"),c=r((function(){a(1)}));i({target:"Object",stat:!0,forced:c,sham:!s},{getPrototypeOf:function(t){return a(o(t))}})},"342f":function(t,e,n){var i=n("d066");t.exports=i("navigator","userAgent")||""},"34c3":function(t,e,n){"use strict";n("498a");var i=n("2b0e");e["a"]=i["a"].extend({name:"v-list-item-icon",functional:!0,render:function(t,e){var n=e.data,i=e.children;return n.staticClass="v-list-item__icon ".concat(n.staticClass||"").trim(),t("div",n,i)}})},"35a1":function(t,e,n){var i=n("f5df"),r=n("3f8c"),o=n("b622"),a=o("iterator");t.exports=function(t){if(void 0!=t)return t[a]||t["@@iterator"]||r[i(t)]}},"368e":function(t,e,n){},"36a7":function(t,e,n){},"37e8":function(t,e,n){var i=n("83ab"),r=n("9bf2"),o=n("825a"),a=n("df75");t.exports=i?Object.defineProperties:function(t,e){o(t);var n,i=a(e),s=i.length,c=0;while(s>c)r.f(t,n=i[c++],e[n]);return t}},3835:function(t,e,n){"use strict";function i(t){if(Array.isArray(t))return t}n.d(e,"a",(function(){return s}));n("a4d3"),n("e01a"),n("d28b"),n("d3b7"),n("3ca3"),n("ddb0");function r(t,e){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(t)){var n=[],i=!0,r=!1,o=void 0;try{for(var a,s=t[Symbol.iterator]();!(i=(a=s.next()).done);i=!0)if(n.push(a.value),e&&n.length===e)break}catch(c){r=!0,o=c}finally{try{i||null==s["return"]||s["return"]()}finally{if(r)throw o}}return n}}var o=n("06c5");function a(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function s(t,e){return i(t)||r(t,e)||Object(o["a"])(t,e)||a()}},"38cb":function(t,e,n){"use strict";n("fb6a"),n("a9e3");var i=n("53ca"),r=n("a9ad"),o=n("7560"),a=n("3206"),s=n("80d2"),c=n("d9bd"),l=n("58df"),u=Object(l["a"])(r["a"],Object(a["a"])("form"),o["a"]);e["a"]=u.extend({name:"validatable",props:{disabled:Boolean,error:Boolean,errorCount:{type:[Number,String],default:1},errorMessages:{type:[String,Array],default:function(){return[]}},messages:{type:[String,Array],default:function(){return[]}},readonly:Boolean,rules:{type:Array,default:function(){return[]}},success:Boolean,successMessages:{type:[String,Array],default:function(){return[]}},validateOnBlur:Boolean,value:{required:!1}},data:function(){return{errorBucket:[],hasColor:!1,hasFocused:!1,hasInput:!1,isFocused:!1,isResetting:!1,lazyValue:this.value,valid:!1}},computed:{computedColor:function(){if(!this.isDisabled)return this.color?this.color:this.isDark&&!this.appIsDark?"white":"primary"},hasError:function(){return this.internalErrorMessages.length>0||this.errorBucket.length>0||this.error},hasSuccess:function(){return this.internalSuccessMessages.length>0||this.success},externalError:function(){return this.internalErrorMessages.length>0||this.error},hasMessages:function(){return this.validationTarget.length>0},hasState:function(){return!this.isDisabled&&(this.hasSuccess||this.shouldValidate&&this.hasError)},internalErrorMessages:function(){return this.genInternalMessages(this.errorMessages)},internalMessages:function(){return this.genInternalMessages(this.messages)},internalSuccessMessages:function(){return this.genInternalMessages(this.successMessages)},internalValue:{get:function(){return this.lazyValue},set:function(t){this.lazyValue=t,this.$emit("input",t)}},isDisabled:function(){return this.disabled||!!this.form&&this.form.disabled},isInteractive:function(){return!this.isDisabled&&!this.isReadonly},isReadonly:function(){return this.readonly||!!this.form&&this.form.readonly},shouldValidate:function(){return!!this.externalError||!this.isResetting&&(this.validateOnBlur?this.hasFocused&&!this.isFocused:this.hasInput||this.hasFocused)},validations:function(){return this.validationTarget.slice(0,Number(this.errorCount))},validationState:function(){if(!this.isDisabled)return this.hasError&&this.shouldValidate?"error":this.hasSuccess?"success":this.hasColor?this.computedColor:void 0},validationTarget:function(){return this.internalErrorMessages.length>0?this.internalErrorMessages:this.successMessages.length>0?this.internalSuccessMessages:this.messages.length>0?this.internalMessages:this.shouldValidate?this.errorBucket:[]}},watch:{rules:{handler:function(t,e){Object(s["i"])(t,e)||this.validate()},deep:!0},internalValue:function(){this.hasInput=!0,this.validateOnBlur||this.$nextTick(this.validate)},isFocused:function(t){t||this.isDisabled||(this.hasFocused=!0,this.validateOnBlur&&this.$nextTick(this.validate))},isResetting:function(){var t=this;setTimeout((function(){t.hasInput=!1,t.hasFocused=!1,t.isResetting=!1,t.validate()}),0)},hasError:function(t){this.shouldValidate&&this.$emit("update:error",t)},value:function(t){this.lazyValue=t}},beforeMount:function(){this.validate()},created:function(){this.form&&this.form.register(this)},beforeDestroy:function(){this.form&&this.form.unregister(this)},methods:{genInternalMessages:function(t){return t?Array.isArray(t)?t:[t]:[]},reset:function(){this.isResetting=!0,this.internalValue=Array.isArray(this.internalValue)?[]:void 0},resetValidation:function(){this.isResetting=!0},validate:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0],e=arguments.length>1?arguments[1]:void 0,n=[];e=e||this.internalValue,t&&(this.hasInput=this.hasFocused=!0);for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:[];return Object(r["a"])(Object(i["b"])(["absolute","fixed"])).extend({name:"applicationable",props:{app:Boolean},computed:{applicationProperty:function(){return t}},watch:{app:function(t,e){e?this.removeApplication(!0):this.callUpdate()},applicationProperty:function(t,e){this.$vuetify.application.unregister(this._uid,e)}},activated:function(){this.callUpdate()},created:function(){for(var t=0,n=e.length;t0&&void 0!==arguments[0]&&arguments[0];(t||this.app)&&this.$vuetify.application.unregister(this._uid,this.applicationProperty)},updateApplication:function(){return 0}}})}},"3ad0":function(t,e,n){},"3bbe":function(t,e,n){var i=n("861d");t.exports=function(t){if(!i(t)&&null!==t)throw TypeError("Can't set "+String(t)+" as a prototype");return t}},"3c93":function(t,e,n){},"3ca3":function(t,e,n){"use strict";var i=n("6547").charAt,r=n("69f3"),o=n("7dd0"),a="String Iterator",s=r.set,c=r.getterFor(a);o(String,"String",(function(t){s(this,{type:a,string:String(t),index:0})}),(function(){var t,e=c(this),n=e.string,r=e.index;return r>=n.length?{value:void 0,done:!0}:(t=i(n,r),e.index+=t.length,{value:t,done:!1})}))},"3ea3":function(t,e,n){var i=n("23e7"),r=n("f748"),o=Math.abs,a=Math.pow;i({target:"Math",stat:!0},{cbrt:function(t){return r(t=+t)*a(o(t),1/3)}})},"3f8c":function(t,e){t.exports={}},4069:function(t,e,n){var i=n("44d2");i("flat")},"408a":function(t,e,n){var i=n("c6b6");t.exports=function(t){if("number"!=typeof t&&"Number"!=i(t))throw TypeError("Incorrect invocation");return+t}},"40dc":function(t,e,n){"use strict";n("a9e3"),n("b680"),n("c7cd");var i=n("5530"),r=(n("8b0d"),n("71d9")),o=n("53ca");function a(t,e){var n=e.modifiers||{},i=n.self,r=void 0!==i&&i,a=e.value,s="object"===Object(o["a"])(a)&&a.options||{passive:!0},c="function"===typeof a||"handleEvent"in a?a:a.handler,l=r?t:e.arg?document.querySelector(e.arg):window;l&&(l.addEventListener("scroll",c,s),t._onScroll={handler:c,options:s,target:r?void 0:l})}function s(t){if(t._onScroll){var e=t._onScroll,n=e.handler,i=e.options,r=e.target,o=void 0===r?t:r;o.removeEventListener("scroll",n,i),delete t._onScroll}}var c={inserted:a,unbind:s},l=c,u=n("3a66"),h=n("d9bd"),f=n("2b0e"),d=f["a"].extend({name:"scrollable",directives:{Scroll:c},props:{scrollTarget:String,scrollThreshold:[String,Number]},data:function(){return{currentScroll:0,currentThreshold:0,isActive:!1,isScrollingUp:!1,previousScroll:0,savedScroll:0,target:null}},computed:{canScroll:function(){return"undefined"!==typeof window},computedScrollThreshold:function(){return this.scrollThreshold?Number(this.scrollThreshold):300}},watch:{isScrollingUp:function(){this.savedScroll=this.savedScroll||this.currentScroll},isActive:function(){this.savedScroll=0}},mounted:function(){this.scrollTarget&&(this.target=document.querySelector(this.scrollTarget),this.target||Object(h["c"])("Unable to locate element with identifier ".concat(this.scrollTarget),this))},methods:{onScroll:function(){var t=this;this.canScroll&&(this.previousScroll=this.currentScroll,this.currentScroll=this.target?this.target.scrollTop:window.pageYOffset,this.isScrollingUp=this.currentScrollt.computedScrollThreshold&&t.thresholdMet()})))},thresholdMet:function(){}}}),p=n("d10f"),v=n("f2e7"),m=n("80d2"),g=n("58df"),b=Object(g["a"])(r["a"],d,p["a"],v["a"],Object(u["a"])("top",["clippedLeft","clippedRight","computedHeight","invertedScroll","isExtended","isProminent","value"]));e["a"]=b.extend({name:"v-app-bar",directives:{Scroll:l},props:{clippedLeft:Boolean,clippedRight:Boolean,collapseOnScroll:Boolean,elevateOnScroll:Boolean,fadeImgOnScroll:Boolean,hideOnScroll:Boolean,invertedScroll:Boolean,scrollOffScreen:Boolean,shrinkOnScroll:Boolean,value:{type:Boolean,default:!0}},data:function(){return{isActive:this.value}},computed:{applicationProperty:function(){return this.bottom?"bottom":"top"},canScroll:function(){return d.options.computed.canScroll.call(this)&&(this.invertedScroll||this.elevateOnScroll||this.hideOnScroll||this.collapseOnScroll||this.isBooted||!this.value)},classes:function(){return Object(i["a"])(Object(i["a"])({},r["a"].options.computed.classes.call(this)),{},{"v-toolbar--collapse":this.collapse||this.collapseOnScroll,"v-app-bar":!0,"v-app-bar--clipped":this.clippedLeft||this.clippedRight,"v-app-bar--fade-img-on-scroll":this.fadeImgOnScroll,"v-app-bar--elevate-on-scroll":this.elevateOnScroll,"v-app-bar--fixed":!this.absolute&&(this.app||this.fixed),"v-app-bar--hide-shadow":this.hideShadow,"v-app-bar--is-scrolled":this.currentScroll>0,"v-app-bar--shrink-on-scroll":this.shrinkOnScroll})},computedContentHeight:function(){if(!this.shrinkOnScroll)return r["a"].options.computed.computedContentHeight.call(this);var t=this.computedOriginalHeight,e=this.dense?48:56,n=t,i=n-e,o=i/this.computedScrollThreshold,a=this.currentScroll*o;return Math.max(e,n-a)},computedFontSize:function(){if(this.isProminent){var t=this.dense?96:128,e=t-this.computedContentHeight,n=.00347;return Number((1.5-e*n).toFixed(2))}},computedLeft:function(){return!this.app||this.clippedLeft?0:this.$vuetify.application.left},computedMarginTop:function(){return this.app?this.$vuetify.application.bar:0},computedOpacity:function(){if(this.fadeImgOnScroll){var t=Math.max((this.computedScrollThreshold-this.currentScroll)/this.computedScrollThreshold,0);return Number(parseFloat(t).toFixed(2))}},computedOriginalHeight:function(){var t=r["a"].options.computed.computedContentHeight.call(this);return this.isExtended&&(t+=parseInt(this.extensionHeight)),t},computedRight:function(){return!this.app||this.clippedRight?0:this.$vuetify.application.right},computedScrollThreshold:function(){return this.scrollThreshold?Number(this.scrollThreshold):this.computedOriginalHeight-(this.dense?48:56)},computedTransform:function(){if(!this.canScroll||this.elevateOnScroll&&0===this.currentScroll&&this.isActive)return 0;if(this.isActive)return 0;var t=this.scrollOffScreen?this.computedHeight:this.computedContentHeight;return this.bottom?t:-t},hideShadow:function(){return this.elevateOnScroll&&this.isExtended?this.currentScroll0:r["a"].options.computed.isCollapsed.call(this)},isProminent:function(){return r["a"].options.computed.isProminent.call(this)||this.shrinkOnScroll},styles:function(){return Object(i["a"])(Object(i["a"])({},r["a"].options.computed.styles.call(this)),{},{fontSize:Object(m["f"])(this.computedFontSize,"rem"),marginTop:Object(m["f"])(this.computedMarginTop),transform:"translateY(".concat(Object(m["f"])(this.computedTransform),")"),left:Object(m["f"])(this.computedLeft),right:Object(m["f"])(this.computedRight)})}},watch:{canScroll:"onScroll",computedTransform:function(){this.canScroll&&(this.clippedLeft||this.clippedRight)&&this.callUpdate()},invertedScroll:function(t){this.isActive=!t||0!==this.currentScroll}},created:function(){this.invertedScroll&&(this.isActive=!1)},methods:{genBackground:function(){var t=r["a"].options.methods.genBackground.call(this);return t.data=this._b(t.data||{},t.tag,{style:{opacity:this.computedOpacity}}),t},updateApplication:function(){return this.invertedScroll?0:this.computedHeight+this.computedTransform},thresholdMet:function(){this.invertedScroll?this.isActive=this.currentScroll>this.computedScrollThreshold:(this.hideOnScroll&&(this.isActive=this.isScrollingUp||this.currentScroll1?arguments[1]:void 0)}})},"466d":function(t,e,n){"use strict";var i=n("d784"),r=n("825a"),o=n("50c4"),a=n("1d80"),s=n("8aa5"),c=n("14c3");i("match",1,(function(t,e,n){return[function(e){var n=a(this),i=void 0==e?void 0:e[t];return void 0!==i?i.call(e,n):new RegExp(e)[t](String(n))},function(t){var i=n(e,t,this);if(i.done)return i.value;var a=r(t),l=String(this);if(!a.global)return c(a,l);var u=a.unicode;a.lastIndex=0;var h,f=[],d=0;while(null!==(h=c(a,l))){var p=String(h[0]);f[d]=p,""===p&&(a.lastIndex=s(l,o(a.lastIndex),u)),d++}return 0===d?null:f}]}))},4804:function(t,e,n){},"480e":function(t,e,n){"use strict";n("7db0");var i=n("7560");e["a"]=i["a"].extend({name:"v-theme-provider",props:{root:Boolean},computed:{isDark:function(){return this.root?this.rootIsDark:i["a"].options.computed.isDark.call(this)}},render:function(){return this.$slots.default&&this.$slots.default.find((function(t){return!t.isComment&&" "!==t.text}))}})},4840:function(t,e,n){var i=n("825a"),r=n("1c0b"),o=n("b622"),a=o("species");t.exports=function(t,e){var n,o=i(t).constructor;return void 0===o||void 0==(n=i(o)[a])?e:r(n)}},4930:function(t,e,n){var i=n("d039");t.exports=!!Object.getOwnPropertySymbols&&!i((function(){return!String(Symbol())}))},"498a":function(t,e,n){"use strict";var i=n("23e7"),r=n("58a8").trim,o=n("c8d2");i({target:"String",proto:!0,forced:o("trim")},{trim:function(){return r(this)}})},"4ad4":function(t,e,n){"use strict";n("caad"),n("45fc"),n("b0c0"),n("b64b");var i=n("53ca"),r=n("16b7"),o=n("f2e7"),a=n("58df"),s=n("80d2"),c=n("d9bd"),l=Object(a["a"])(r["a"],o["a"]);e["a"]=l.extend({name:"activatable",props:{activator:{default:null,validator:function(t){return["string","object"].includes(Object(i["a"])(t))}},disabled:Boolean,internalActivator:Boolean,openOnHover:Boolean,openOnFocus:Boolean},data:function(){return{activatorElement:null,activatorNode:[],events:["click","mouseenter","mouseleave","focus"],listeners:{}}},watch:{activator:"resetActivator",openOnFocus:"resetActivator",openOnHover:"resetActivator"},mounted:function(){var t=Object(s["p"])(this,"activator",!0);t&&["v-slot","normal"].includes(t)&&Object(c["b"])('The activator slot must be bound, try \'