diff --git a/CMakeLists.txt b/CMakeLists.txt index 459022b..bd5ccab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,19 +3,26 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(ENV{TARGET} "x86_64-linux-gnu") - -set(CMAKE_CXX_FLAGS "-Wall -fvisibility=hidden -fvisibility-inlines-hidden -Wformat -Wformat-security") +set(CMAKE_CXX_FLAGS + "-Wall -fvisibility=hidden -fvisibility-inlines-hidden -Wformat -Wformat-security -rdynamic" +) set(CMAKE_CXX_FLAGS_DEBUG "-g2 -O0") -set(CMAKE_CXX_FLAGS_RELEASE "-fstack-protector-all -Wl,-z,relro,-z,now -Wl,-z,noexecstack -s -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -O3 -g2 -march=native -pipe -flto=auto") +set(CMAKE_CXX_FLAGS_RELEASE + "-fstack-protector-all -Wl,-z,relro,-z,now -Wl,-z,noexecstack -s -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -O3 -g2 -march=native -pipe -flto=auto" +) list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") enable_testing() -execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/version.sh - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE MQTTD_VERSION) +execute_process( + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/version.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE MQTTD_VERSION) -project(mqttd VERSION ${MQTTD_VERSION} LANGUAGES CXX) +project( + mqttd + VERSION ${MQTTD_VERSION} + LANGUAGES CXX) add_subdirectory(src) add_subdirectory(tests) diff --git a/cmake/FindAutotools.cmake b/cmake/FindAutotools.cmake index bc69aff..357d796 100644 --- a/cmake/FindAutotools.cmake +++ b/cmake/FindAutotools.cmake @@ -6,7 +6,7 @@ FindAutotools ------------- -The main purpose is to detect that commonly used Autotools programs are isntalled. +The main purpose is to detect that commonly used Autotools programs are installed. This lets the user know at CMake configuration time if the computer is ready to build an autotools-based ExternalProject. diff --git a/cmake/GetCppTrace.cmake b/cmake/GetCppTrace.cmake new file mode 100644 index 0000000..7ee7421 --- /dev/null +++ b/cmake/GetCppTrace.cmake @@ -0,0 +1,14 @@ +include(FetchContent) + +set(CPPTRACE_UNWIND_WITH_UNWIND Off) +set(CPPTRACE_UNWIND_WITH_LIBUNWIND On) +set(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF Off) +set(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE On) +set(CPPTRACE_ADDR2LINE_SEARCH_SYSTEM_PATH On) +FetchContent_Declare( + cpptrace + GIT_REPOSITORY https://github.com/jeremy-rifkin/cpptrace.git + GIT_TAG v0.5.2 # + GIT_PROGRESS TRUE + OVERRIDE_FIND_PACKAGE) +FetchContent_MakeAvailable(cpptrace) diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 758e743..6e66aa6 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -30,10 +30,16 @@ set(DOXYGEN_SORT_BY_SCOPE_NAME YES) set(DOXYGEN_SORT_MEMBER_DOCS NO) set(DOXYGEN_SOURCE_BROWSER YES) set(DOXYGEN_STRIP_CODE_COMMENTS NO) +set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md") +set(DOXYGEN_EXTRA_FILES "${CMAKE_SOURCE_DIR}/docs/mqtt_spec/") -doxygen_add_docs(doc - "${CMAKE_SOURCE_DIR}/src" - "${CMAKE_SOURCE_DIR}/tests" - ALL - COMMENT "Generate HTML documentation") +doxygen_add_docs( + doc "${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/tests" + "${CMAKE_SOURCE_DIR}/README.md" ALL COMMENT "Generate HTML documentation") +add_custom_target( + open_docs + COMMAND ${CMAKE_COMMAND} -E env xdg-open + ${CMAKE_SOURCE_DIR}/build/docs/html/index.html + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/build/docs/html + COMMENT "Opening Doxygen documentation") diff --git a/docs/mqtt_spec/MQTT Version 5.0.html b/docs/mqtt_spec/MQTT Version 5.0.html new file mode 100644 index 0000000..644f816 --- /dev/null +++ b/docs/mqtt_spec/MQTT Version 5.0.html @@ -0,0 +1,27425 @@ + + + + + +MQTT Version 5.0 + + + + + + +
+ +

+OASIS logo

+ +
+ +

MQTT Version 5.0

+ +

OASIS Standard

+ +

07 March 2019

+ +
+ +

Specification URIs

+ +

This version:

+ +

https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.docx (Authoritative)

+ +

https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html

+ +

https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.pdf

+ +

Previous version:

+ +

http://docs.oasis-open.org/mqtt/mqtt/v5.0/cos01/mqtt-v5.0-cos01.docx (Authoritative)

+ +

http://docs.oasis-open.org/mqtt/mqtt/v5.0/cos01/mqtt-v5.0-cos01.html

+ +

http://docs.oasis-open.org/mqtt/mqtt/v5.0/cos01/mqtt-v5.0-cos01.pdf

+ +

Latest version:

+ +

https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.docx (Authoritative)

+ +

https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html

+ +

https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.pdf

+ +

Technical Committee:

+ +

OASIS Message Queuing +Telemetry Transport (MQTT) TC

+ +

Chairs:

+ +

Richard Coppen (coppen@uk.ibm.com), IBM

+ +

Editors:

+ +

Andrew Banks (andrew_banks@uk.ibm.com), IBM

+ +

Ed Briggs (edbriggs@microsoft.com), Microsoft

+ +

Ken Borgendale (kwb@us.ibm.com), +IBM

+ +

Rahul Gupta (rahul.gupta@us.ibm.com), IBM

+ +

Related work:

+ +

This specification replaces or supersedes:

+ +

·         +MQTT Version 3.1.1. Edited by Andrew Banks and Rahul +Gupta. 29 October 2014. OASIS Standard. http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html. +Latest version: http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html.

+ +

This specification is related to:

+ +

·         +MQTT and the NIST Cybersecurity Framework Version 1.0. +Edited by Geoff Brown and Louis-Philippe Lamoureux. Latest +version: http://docs.oasis-open.org/mqtt/mqtt-nist-cybersecurity/v1.0/mqtt-nist-cybersecurity-v1.0.html.

+ +

Abstract:

+ +

MQTT is a Client Server publish/subscribe messaging transport +protocol. It is light weight, open, simple, and designed to be easy to +implement. These characteristics make it ideal for use in many situations, +including constrained environments such as for communication in Machine to +Machine (M2M) and Internet of Things (IoT) contexts where a small code +footprint is required and/or network bandwidth is at a premium.

+ +

The protocol runs over TCP/IP, or over other network +protocols that provide ordered, lossless, bi-directional connections. Its +features include:

+ +

·         +Use of the publish/subscribe message pattern which provides +one-to-many message distribution and decoupling of applications.

+ +

·         +A messaging transport that is agnostic to the content of the +payload.

+ +

·         +Three qualities of service for message delivery:

+ +

o    +"At most once", where messages are delivered according +to the best efforts of the operating environment. Message loss can occur. This +level could be used, for example, with ambient sensor data where it does not +matter if an individual reading is lost as the next one will be published soon +after.

+ +

o    +"At least once", where messages are assured to arrive +but duplicates can occur.

+ +

o    +"Exactly once", where messages are assured to arrive +exactly once. This level could be used, for example, with billing systems where +duplicate or lost messages could lead to incorrect charges being applied.

+ +

·         +A small transport overhead and protocol exchanges minimized to +reduce network traffic.

+ +

·         +A mechanism to notify interested parties when an abnormal disconnection +occurs.

+ +

Status:

+ +

This document was last revised or approved by the membership +of OASIS on the above date. The level of approval is also listed above. Check +the “Latest version” location noted above for possible later revisions of this +document. Any other numbered Versions and other technical work produced by the +Technical Committee (TC) are listed at https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=mqtt#technical.

+ +

TC members should send comments on this document to the TC’s +email list. Others should send comments to the TC’s public comment list, after +subscribing to it by following the instructions at the “Send +A Comment” button on the TC’s web page at https://www.oasis-open.org/committees/mqtt/.

+ +

This specification is provided under the Non-Assertion +Mode of the OASIS +IPR Policy, the mode chosen when the Technical Committee was established. For +information on whether any patents have been disclosed that may be essential to +implementing this specification, and any offers of patent licensing terms, +please refer to the Intellectual Property Rights section of the TC’s web page (https://www.oasis-open.org/committees/mqtt/ipr.php).

+ +

Note that any machine-readable content (Computer +Language Definitions) declared Normative for this Work Product is provided +in separate plain text files. In the event of a discrepancy between any such +plain text file and display content in the Work Product's prose narrative document(s), +the content in the separate plain text file prevails.

+ +

Citation format:

+ +

When referencing this specification the following citation +format should be used:

+ +

[mqtt-v5.0]

+ +

MQTT Version 5.0. Edited by Andrew +Banks, Ed Briggs, Ken Borgendale, and Rahul Gupta. 07 March 2019. OASIS +Standard. https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html. Latest version: https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html.

+ +
+ +

Notices

+ +
+ +

Copyright © OASIS Open 2019. All Rights Reserved.

+ +

All capitalized terms in the following text have the +meanings assigned to them in the OASIS Intellectual Property Rights Policy (the +"OASIS IPR Policy"). The full Policy may be +found at the OASIS website.

+ +

This document and translations of it may be copied and +furnished to others, and derivative works that comment on or otherwise explain +it or assist in its implementation may be prepared, copied, published, and +distributed, in whole or in part, without restriction of any kind, provided +that the above copyright notice and this section are included on all such copies +and derivative works. However, this document itself may not be modified in any +way, including by removing the copyright notice or references to OASIS, except +as needed for the purpose of developing any document or deliverable produced by +an OASIS Technical Committee (in which case the rules applicable to copyrights, +as set forth in the OASIS IPR Policy, must be followed) or as required to +translate it into languages other than English.

+ +

The limited permissions granted above are perpetual and will +not be revoked by OASIS or its successors or assigns.

+ +

This document and the information contained herein is +provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF +THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED +WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

+ +

OASIS requests that any OASIS Party or any other party that +believes it has patent claims that would necessarily be infringed by +implementations of this OASIS Committee Specification or OASIS Standard, to +notify OASIS TC Administrator and provide an indication of its willingness to +grant patent licenses to such patent claims in a manner consistent with the IPR +Mode of the OASIS Technical Committee that produced this specification.

+ +

OASIS invites any party to contact the OASIS TC +Administrator if it is aware of a claim of ownership of any patent claims that +would necessarily be infringed by implementations of this specification by a +patent holder that is not willing to provide a license to such patent claims in +a manner consistent with the IPR Mode of the OASIS Technical Committee that +produced this specification. OASIS may include such claims on its website, but +disclaims any obligation to do so.

+ +

OASIS takes no position regarding the validity or scope of +any intellectual property or other rights that might be claimed to pertain to +the implementation or use of the technology described in this document or the +extent to which any license under such rights might or might not be available; +neither does it represent that it has made any effort to identify any such +rights. Information on OASIS' procedures with respect to rights in any document +or deliverable produced by an OASIS Technical Committee can be found on the +OASIS website. Copies of claims of rights made available for publication and +any assurances of licenses to be made available, or the result of an attempt +made to obtain a general license or permission for the use of such proprietary +rights by implementers or users of this OASIS Committee Specification or OASIS +Standard, can be obtained from the OASIS TC Administrator. OASIS makes no +representation that any information or list of intellectual property rights +will at any time be complete, or that any claims in such list are, in fact, +Essential Claims.

+ +

The name "OASIS" is a trademark of OASIS, the owner and developer of this +specification, and should be used only to refer to the organization and its +official outputs. OASIS welcomes reference to, and implementation and use of, +specifications, while reserving the right to enforce its marks against misleading +uses. Please see https://www.oasis-open.org/policies-guidelines/trademark +for above guidance.

+ +
+ +

Table of Contents

+ +
+ +

1        Introduction. 11

+ +

1.0 +Intellectual property rights policy. 11

+ +

1.1 +Organization of the MQTT specification. 11

+ +

1.2 +Terminology. 11

+ +

1.3 Normative +references. 13

+ +

1.4 +Non-normative references. 13

+ +

1.5 Data +representation. 16

+ +

1.5.1 Bits. 16

+ +

1.5.2 Two Byte +Integer 16

+ +

1.5.3 Four +Byte Integer 16

+ +

1.5.4 UTF-8 +Encoded String. 16

+ +

1.5.5 Variable +Byte Integer 18

+ +

1.5.6 Binary +Data. 19

+ +

1.5.7 UTF-8 +String Pair 19

+ +

1.6 Security. 19

+ +

1.7 Editing +convention. 20

+ +

1.8 Change +history. 20

+ +

1.8.1 MQTT +v3.1.1. 20

+ +

1.8.2 MQTT +v5.0. 20

+ +

2        MQTT +Control Packet format 21

+ +

2.1 Structure +of an MQTT Control Packet 21

+ +

2.1.1 Fixed +Header 21

+ +

2.1.2 MQTT +Control Packet type. 21

+ +

2.1.3 Flags. 22

+ +

2.1.4 +Remaining Length. 23

+ +

2.2 Variable +Header 23

+ +

2.2.1 Packet +Identifier 23

+ +

2.2.2 +Properties. 25

+ +

2.2.2.1 +Property Length. 25

+ +

2.2.2.2 +Property. 25

+ +

2.3 Payload. 26

+ +

2.4 Reason +Code. 27

+ +

3        MQTT +Control Packets. 30

+ +

3.1 CONNECT – +Connection Request 30

+ +

3.1.1 CONNECT +Fixed Header 30

+ +

3.1.2 CONNECT +Variable Header 30

+ +

3.1.2.1 +Protocol Name. 30

+ +

3.1.2.2 +Protocol Version. 31

+ +

3.1.2.3 +Connect Flags. 31

+ +

3.1.2.4 Clean +Start 32

+ +

3.1.2.5 Will +Flag. 32

+ +

3.1.2.6 Will +QoS.. 33

+ +

3.1.2.7 Will +Retain. 33

+ +

3.1.2.8 User +Name Flag. 33

+ +

3.1.2.9 +Password Flag. 33

+ +

3.1.2.10 Keep +Alive. 34

+ +

3.1.2.11 +CONNECT Properties. 34

+ +

3.1.2.11.1 +Property Length. 34

+ +

3.1.2.11.2 Session Expiry Interval 35

+ +

3.1.2.11.3 +Receive Maximum... 36

+ +

3.1.2.11.4 +Maximum Packet Size. 36

+ +

3.1.2.11.5 +Topic Alias Maximum... 37

+ +

3.1.2.11.6 +Request Response Information. 37

+ +

3.1.2.11.7 +Request Problem Information. 37

+ +

3.1.2.11.8 +User Property. 38

+ +

3.1.2.11.9 +Authentication Method. 38

+ +

3.1.2.11.10 +Authentication Data. 38

+ +

3.1.2.12 +Variable Header non-normative example. 39

+ +

3.1.3 CONNECT +Payload. 40

+ +

3.1.3.1 Client +Identifier (ClientID) 40

+ +

3.1.3.2 Will +Properties. 40

+ +

3.1.3.2.1 +Property Length. 40

+ +

3.1.3.2.2 Will +Delay Interval 41

+ +

3.1.3.2.3 +Payload Format Indicator 41

+ +

3.1.3.2.4 +Message Expiry Interval 41

+ +

3.1.3.2.5 +Content Type. 42

+ +

3.1.3.2.6 +Response Topic. 42

+ +

3.1.3.2.7 +Correlation Data. 42

+ +

3.1.3.2.8 User +Property. 42

+ +

3.1.3.3 Will +Topic. 42

+ +

3.1.3.4 Will +Payload. 43

+ +

3.1.3.5 User +Name. 43

+ +

3.1.3.6 +Password. 43

+ +

3.1.4 CONNECT +Actions. 43

+ +

3.2 CONNACK – +Connect acknowledgement 44

+ +

3.2.1 CONNACK +Fixed Header 45

+ +

3.2.2 CONNACK +Variable Header 45

+ +

3.2.2.1 +Connect Acknowledge Flags. 45

+ +

3.2.2.1.1 +Session Present 45

+ +

3.2.2.2 +Connect Reason Code. 46

+ +

3.2.2.3 +CONNACK Properties. 47

+ +

3.2.2.3.1 +Property Length. 47

+ +

3.2.2.3.2 Session Expiry Interval 47

+ +

3.2.2.3.3 +Receive Maximum... 48

+ +

3.2.2.3.4 +Maximum QoS.. 48

+ +

3.2.2.3.5 +Retain Available. 49

+ +

3.2.2.3.6 +Maximum Packet Size. 49

+ +

3.2.2.3.7 +Assigned Client Identifier 49

+ +

3.2.2.3.8 +Topic Alias Maximum... 50

+ +

3.2.2.3.9 +Reason String. 50

+ +

3.2.2.3.10 +User Property. 50

+ +

3.2.2.3.11 +Wildcard Subscription Available. 50

+ +

3.2.2.3.12 +Subscription Identifiers Available. 51

+ +

3.2.2.3.13 +Shared Subscription Available. 51

+ +

3.2.2.3.14 +Server Keep Alive. 51

+ +

3.2.2.3.15 +Response Information. 52

+ +

3.2.2.3.16 +Server Reference. 52

+ +

3.2.2.3.17 +Authentication Method. 52

+ +

3.2.2.3.18 +Authentication Data. 52

+ +

3.2.3 CONNACK +Payload. 53

+ +

3.3 PUBLISH – +Publish message. 53

+ +

3.3.1 PUBLISH +Fixed Header 53

+ +

3.3.1.1 DUP.. 53

+ +

3.3.1.2 QoS.. 54

+ +

3.3.1.3 RETAIN.. 54

+ +

3.3.1.4 +Remaining Length. 55

+ +

3.3.2 PUBLISH +Variable Header 55

+ +

3.3.2.1 Topic +Name. 55

+ +

3.3.2.2 Packet +Identifier 56

+ +

3.3.2.3 +PUBLISH Properties. 56

+ +

3.3.2.3.1 +Property Length. 56

+ +

3.3.2.3.2 +Payload Format Indicator 56

+ +

3.3.2.3.3 +Message Expiry Interval` 56

+ +

3.3.2.3.4 +Topic Alias. 57

+ +

3.3.2.3.5 +Response Topic. 58

+ +

3.3.2.3.6 +Correlation Data. 58

+ +

3.3.2.3.7 User +Property. 58

+ +

3.3.2.3.8 +Subscription Identifier 59

+ +

3.3.2.3.9 +Content Type. 59

+ +

3.3.3 PUBLISH +Payload. 60

+ +

3.3.4 PUBLISH +Actions. 60

+ +

3.4 PUBACK – +Publish acknowledgement 62

+ +

3.4.1 PUBACK +Fixed Header 63

+ +

3.4.2 PUBACK +Variable Header 63

+ +

3.4.2.1 PUBACK +Reason Code. 63

+ +

3.4.2.2 PUBACK +Properties. 64

+ +

3.4.2.2.1 +Property Length. 64

+ +

3.4.2.2.2 +Reason String. 64

+ +

3.4.2.2.3 User +Property. 64

+ +

3.4.3 PUBACK +Payload. 65

+ +

3.4.4 PUBACK +Actions. 65

+ +

3.5 PUBREC – +Publish received (QoS 2 delivery part 1) 65

+ +

3.5.1 PUBREC +Fixed Header 65

+ +

3.5.2 PUBREC +Variable Header 65

+ +

3.5.2.1 PUBREC +Reason Code. 65

+ +

3.5.2.2 PUBREC +Properties. 66

+ +

3.5.2.2.1 +Property Length. 66

+ +

3.5.2.2.2 +Reason String. 66

+ +

3.5.2.2.3 User +Property. 67

+ +

3.5.3 PUBREC +Payload. 67

+ +

3.5.4 PUBREC +Actions. 67

+ +

3.6 PUBREL – +Publish release (QoS 2 delivery part 2) 67

+ +

3.6.1 PUBREL +Fixed Header 67

+ +

3.6.2 PUBREL +Variable Header 67

+ +

3.6.2.1 PUBREL +Reason Code. 68

+ +

3.6.2.2 PUBREL +Properties. 68

+ +

3.6.2.2.1 +Property Length. 68

+ +

3.6.2.2.2 +Reason String. 68

+ +

3.6.2.2.3 User +Property. 69

+ +

3.6.3 PUBREL +Payload. 69

+ +

3.6.4 PUBREL +Actions. 69

+ +

3.7 PUBCOMP – +Publish complete (QoS 2 delivery part 3) 69

+ +

3.7.1 PUBCOMP +Fixed Header 69

+ +

3.7.2 PUBCOMP +Variable Header 69

+ +

3.7.2.1 +PUBCOMP Reason Code. 70

+ +

3.7.2.2 +PUBCOMP Properties. 70

+ +

3.7.2.2.1 +Property Length. 70

+ +

3.7.2.2.2 +Reason String. 70

+ +

3.7.2.2.3 User +Property. 70

+ +

3.7.3 PUBCOMP +Payload. 71

+ +

3.7.4 PUBCOMP +Actions. 71

+ +

3.8 SUBSCRIBE +- Subscribe request 71

+ +

3.8.1 +SUBSCRIBE Fixed Header 71

+ +

3.8.2 +SUBSCRIBE Variable Header 71

+ +

3.8.2.1 +SUBSCRIBE Properties. 72

+ +

3.8.2.1.1 +Property Length. 72

+ +

3.8.2.1.2 +Subscription Identifier 72

+ +

3.8.2.1.3 User +Property. 72

+ +

3.8.3 +SUBSCRIBE Payload. 72

+ +

3.8.3.1 +Subscription Options. 73

+ +

3.8.4 SUBSCRIBE +Actions. 75

+ +

3.9 SUBACK – +Subscribe acknowledgement 77

+ +

3.9.1 SUBACK +Fixed Header 77

+ +

3.9.2 SUBACK +Variable Header 77

+ +

3.9.2.1 SUBACK +Properties. 77

+ +

3.9.2.1.1 +Property Length. 77

+ +

3.9.2.1.2 +Reason String. 78

+ +

3.9.2.1.3 User +Property. 78

+ +

3.9.3 SUBACK +Payload. 78

+ +

3.10 +UNSUBSCRIBE – Unsubscribe request 79

+ +

3.10.1 +UNSUBSCRIBE Fixed Header 79

+ +

3.10.2 +UNSUBSCRIBE Variable Header 80

+ +

3.10.2.1 +UNSUBSCRIBE Properties. 80

+ +

3.10.2.1.1 +Property Length. 80

+ +

3.10.2.1.2 +User Property. 80

+ +

3.10.3 +UNSUBSCRIBE Payload. 80

+ +

3.10.4 +UNSUBSCRIBE Actions. 81

+ +

3.11 UNSUBACK +– Unsubscribe acknowledgement 81

+ +

3.11.1 +UNSUBACK Fixed Header 82

+ +

3.11.2 +UNSUBACK Variable Header 82

+ +

3.11.2.1 +UNSUBACK Properties. 82

+ +

3.11.2.1.1 +Property Length. 82

+ +

3.11.2.1.2 +Reason String. 82

+ +

3.11.2.1.3 +User Property. 83

+ +

3.11.3 +UNSUBACK Payload. 83

+ +

3.12 PINGREQ – +PING request 83

+ +

3.12.1 PINGREQ +Fixed Header 84

+ +

3.12.2 PINGREQ +Variable Header 84

+ +

3.12.3 PINGREQ +Payload. 84

+ +

3.12.4 PINGREQ +Actions. 84

+ +

3.13 PINGRESP +– PING response. 84

+ +

3.13.1 +PINGRESP Fixed Header 84

+ +

3.13.2 +PINGRESP Variable Header 85

+ +

3.13.3 +PINGRESP Payload. 85

+ +

3.13.4 +PINGRESP Actions. 85

+ +

3.14 +DISCONNECT – Disconnect notification. 85

+ +

3.14.1 +DISCONNECT Fixed Header 85

+ +

3.14.2 +DISCONNECT Variable Header 85

+ +

3.14.2.1 +Disconnect Reason Code. 86

+ +

3.14.2.2 +DISCONNECT Properties. 88

+ +

3.14.2.2.1 +Property Length. 88

+ +

3.14.2.2.2 +Session Expiry Interval 88

+ +

3.14.2.2.3 +Reason String. 88

+ +

3.14.2.2.4 +User Property. 88

+ +

3.14.2.2.5 +Server Reference. 88

+ +

3.14.3 DISCONNECT +Payload. 89

+ +

3.14.4 +DISCONNECT Actions. 89

+ +

3.15 AUTH – +Authentication exchange. 89

+ +

3.15.1 AUTH +Fixed Header 90

+ +

3.15.2 AUTH +Variable Header 90

+ +

3.15.2.1 +Authenticate Reason Code. 90

+ +

3.15.2.2 AUTH +Properties. 90

+ +

3.15.2.2.1 +Property Length. 90

+ +

3.15.2.2.2 +Authentication Method. 91

+ +

3.15.2.2.3 +Authentication Data. 91

+ +

3.15.2.2.4 +Reason String. 91

+ +

3.15.2.2.5 +User Property. 91

+ +

3.15.3 AUTH +Payload. 91

+ +

3.15.4 AUTH +Actions. 91

+ +

4        Operational +behavior 92

+ +

4.1 Session +State. 92

+ +

4.1.1 Storing +Session State. 92

+ +

4.1.2 Session +State non-normative examples. 93

+ +

4.2 Network +Connections. 93

+ +

4.3 Quality of +Service levels and protocol flows. 93

+ +

4.3.1 QoS 0: +At most once delivery. 94

+ +

4.3.2 QoS 1: +At least once delivery. 94

+ +

4.3.3 QoS 2: +Exactly once delivery. 95

+ +

4.4 Message +delivery retry. 96

+ +

4.5 Message +receipt 97

+ +

4.6 Message +ordering. 97

+ +

4.7 Topic +Names and Topic Filters. 98

+ +

4.7.1 Topic +wildcards. 98

+ +

4.7.1.1 Topic +level separator 98

+ +

4.7.1.2 +Multi-level wildcard. 98

+ +

4.7.1.3 +Single-level wildcard. 99

+ +

4.7.2 Topics +beginning with $. 99

+ +

4.7.3 Topic +semantic and usage. 100

+ +

4.8 +Subscriptions. 101

+ +

4.8.1 Non‑shared +Subscriptions. 101

+ +

4.8.2 Shared +Subscriptions. 101

+ +

4.9 Flow Control 103

+ +

4.10 Request / +Response. 104

+ +

4.10.1 Basic +Request Response (non-normative) 104

+ +

4.10.2 +Determining a Response Topic value (non-normative) 105

+ +

4.11 Server +redirection. 106

+ +

4.12 Enhanced +authentication. 106

+ +

4.12.1 +Re-authentication. 108

+ +

4.13 Handling +errors. 109

+ +

4.13.1 +Malformed Packet and Protocol Errors. 109

+ +

4.13.2 Other +errors. 110

+ +

5        Security +(non-normative) 111

+ +

5.1 +Introduction. 111

+ +

5.2 MQTT +solutions: security and certification. 111

+ +

5.3 +Lightweight crytography and constrained devices. 112

+ +

5.4 +Implementation notes. 112

+ +

5.4.1 +Authentication of Clients by the Server 112

+ +

5.4.2 +Authorization of Clients by the Server 112

+ +

5.4.3 +Authentication of the Server by the Client 113

+ +

5.4.4 +Integrity of Application Messages and MQTT Control Packets. 113

+ +

5.4.5 Privacy +of Application Messages and MQTT Control Packets. 113

+ +

5.4.6 +Non-repudiation of message transmission. 114

+ +

5.4.7 +Detecting compromise of Clients and Servers. 114

+ +

5.4.8 +Detecting abnormal behaviors. 114

+ +

5.4.9 Handling +of Disallowed Unicode code points. 115

+ +

5.4.9.1 +Considerations for the use of Disallowed Unicode code points. 115

+ +

5.4.9.2 +Interactions between Publishers and Subscribers. 115

+ +

5.4.9.3 +Remedies. 116

+ +

5.4.10 Other +security considerations. 116

+ +

5.4.11 Use of +SOCKS. 116

+ +

5.4.12 +Security profiles. 117

+ +

5.4.12.1 Clear +communication profile. 117

+ +

5.4.12.2 +Secured network communication profile. 117

+ +

5.4.12.3 +Secured transport profile. 117

+ +

5.4.12.4 +Industry specific security profiles. 117

+ +

6        Using +WebSocket as a network transport 118

+ +

6.1 IANA +considerations. 118

+ +

7        Conformance. 119

+ +

7.1 +Conformance clauses. 119

+ +

7.1.1 MQTT +Server conformance clause. 119

+ +

7.1.2 MQTT +Client conformance clause. 119

+ +

Appendix A. +Acknowledgments. 120

+ +

Appendix B. +Mandatory normative statement (non-normative) 121

+ +

Appendix C. +Summary of new features in MQTT v5.0 (non-normative) 136

+ +

 

+ +

 

+ +
+ +
+
+ +
+ +
+ +

1      +Introduction

+ +
+ +

1.0 Intellectual property +rights policy

+ +

This specification is provided under the Non-Assertion +Mode of the OASIS +IPR Policy, the mode chosen when the Technical Committee was established. For +information on whether any patents have been disclosed that may be essential to +implementing this specification, and any offers of patent licensing terms, +please refer to the Intellectual Property Rights section of the TC’s web page (https://www.oasis-open.org/committees/mqtt/ipr.php).

+ +

1.1 Organization of the MQTT specification

+ +

The specification is split into seven chapters:

+ +

·         +Chapter 1 - Introduction

+ +

·         +Chapter +2 - MQTT Control Packet format

+ +

·         +Chapter +3 - MQTT Control Packets

+ +

·         +Chapter +4 - Operational behavior

+ +

·         +Chapter 5 - Security

+ +

·         +Chapter 6 - Using WebSocket as a +network transport

+ +

·         +Chapter 7 - Conformance Targets

+ +

 

+ +

1.2 +Terminology

+ +

The key +words "MUST", "MUST NOT", "REQUIRED", +"SHALL", "SHALL NOT", "SHOULD", "SHOULD +NOT", "RECOMMENDED", "MAY", and "OPTIONAL" +in this specification are to be interpreted as described in IETF RFC 2119 [RFC2119], except where they appear in text that is marked +as non-normative.

+ +

 

+ +

Network +Connection:

+ +

A construct provided by the underlying +transport protocol that is being used by MQTT.

+ +

·         +It +connects the Client to the Server.

+ +

·         +It +provides the means to send an ordered, lossless, stream of bytes in both +directions.

+ +

Refer to section 4.2 Network +Connection for non-normative examples.

+ +

 

+ +

Application +Message:

+ +

The data carried by the MQTT protocol across the network for +the application. When an Application Message is transported by MQTT it contains +payload data, a Quality of Service (QoS), a collection of Properties, and a +Topic Name.

+ +

 

+ +

Client:

+ +

A program or device that uses MQTT. A Client:

+ +

·         +opens the Network Connection to the Server

+ +

·         +publishes Application Messages that other Clients might be +interested in.

+ +

·         +subscribes to request Application Messages that it is interested +in receiving.

+ +

·         +unsubscribes to remove a request for Application Messages.

+ +

·         +closes the Network Connection to the Server.

+ +

 

+ +

Server:

+ +

A program or device that acts as an intermediary between +Clients which publish Application Messages and Clients which have made +Subscriptions. A Server:

+ +

·         +accepts Network Connections from Clients.

+ +

·         +accepts Application Messages published by Clients.

+ +

·         +processes Subscribe and Unsubscribe requests from Clients.

+ +

·         +forwards Application Messages that match Client Subscriptions.

+ +

·         +closes the Network Connection from the Client.

+ +

 

+ +

Session:

+ +

A stateful interaction between a Client and a Server. Some +Sessions last only as long as the Network Connection, others can span multiple +consecutive Network Connections between a Client and a Server.

+ +

 

+ +

Subscription:

+ +

A Subscription comprises a Topic Filter and a maximum QoS. A +Subscription is associated with a single Session. A Session can contain more +than one Subscription. Each Subscription within a Session has a different Topic +Filter.

+ +

 

+ +

Shared Subscription:

+ +

A Shared Subscription comprises a Topic Filter and a maximum +QoS. A Shared Subscription can be associated with more than one Session to +allow a wider range of message exchange patterns. An Application Message that +matches a Shared Subscription is only sent to the Client associated with one of +these Sessions. A Session can subscribe to more than one Shared Subscription +and can contain both Shared Subscriptions and Subscriptions which are not +shared.

+ +

 

+ +

Wildcard Subscription:

+ +

A Wildcard Subscription is a Subscription with a Topic +Filter containing one or more wildcard characters. This allows the subscription +to match more than one Topic Name. Refer to section +4.7 for a description of wildcard characters in a Topic Filter.

+ +

 

+ +

Topic Name:

+ +

The label attached to an Application Message which is +matched against the Subscriptions known to the Server.

+ +

 

+ +

Topic Filter:

+ +

An expression contained in a Subscription to indicate an +interest in one or more topics. A Topic Filter can include wildcard characters.

+ +

 

+ +

MQTT Control Packet:

+ +

A packet of information that is sent across the Network +Connection. The MQTT specification defines fifteen different types of MQTT Control +Packet, for example the PUBLISH packet is used to convey Application Messages.

+ +

 

+ +

Malformed Packet:

+ +

A control packet that cannot be parsed according to this +specification. Refer to section 4.13 for +information about error handling.

+ +

 

+ +

Protocol Error:

+ +

An error that is detected after the packet has been parsed +and found to contain data that is not allowed by the protocol or is +inconsistent with the state of the Client or Server. Refer to section 4.13 for information about error handling.

+ +

 

+ +

Will Message:

+ +

An Application Message which is published by the Server +after the Network Connection is closed in cases where the Network Connection is +not closed normally. Refer to section 3.1.2.5 for +information about Will Messages.

+ +

 

+ +

Disallowed Unicode code point:

+ +

The set of Unicode Control Codes and Unicode Noncharacters +which should not be included in a UTF-8 Encoded String. Refer to section 1.5.4 for +more information about the Disallowed Unicode code points.

+ +

 

+ +

1.3 Normative references

+ +

[RFC2119]

+ +

Bradner, S., "Key words for use in RFCs to Indicate +Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997,

+ +

http://www.rfc-editor.org/info/rfc2119

+ +

 

+ +

[RFC3629]

+ +

Yergeau, F., "UTF-8, a transformation format of ISO +10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 2003,

+ +

http://www.rfc-editor.org/info/rfc3629

+ +

 

+ +

[RFC6455]

+ +

Fette, I. and A. Melnikov, "The WebSocket +Protocol", RFC 6455, DOI 10.17487/RFC6455, December 2011,

+ +

http://www.rfc-editor.org/info/rfc6455

+ +

 

+ +

[Unicode]

+ +

The Unicode Consortium. The Unicode Standard,

+ +

http://www.unicode.org/versions/latest/

+ +

 

+ +

1.4 Non-normative references

+ +

[RFC0793]

+ +

Postel, J., "Transmission Control Protocol", STD +7, RFC 793, DOI 10.17487/RFC0793, September 1981, http://www.rfc-editor.org/info/rfc793

+ +

 

+ +

[RFC5246]

+ +

Dierks, T. and E. Rescorla, "The Transport Layer +Security (TLS) Protocol Version 1.2", RFC 5246, DOI 10.17487/RFC5246, +August 2008,

+ +

http://www.rfc-editor.org/info/rfc5246

+ +

 

+ +

[AES]

+ +

Advanced Encryption Standard (AES) (FIPS PUB 197).

+ +

https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf

+ +

 

+ +

[CHACHA20]

+ +

ChaCha20 and Poly1305 for IETF Protocols

+ +

https://tools.ietf.org/html/rfc7539

+ +

 

+ +

[FIPS1402]

+ +

Security Requirements for Cryptographic Modules (FIPS PUB +140-2)

+ +

https://csrc.nist.gov/csrc/media/publications/fips/140/2/final/documents/fips1402.pdf

+ +

 

+ +

[IEEE 802.1AR]

+ +

IEEE Standard for Local and metropolitan area networks - +Secure Device Identity

+ +

http://standards.ieee.org/findstds/standard/802.1AR-2009.html

+ +

 

+ +

[ISO29192]

+ +

ISO/IEC 29192-1:2012 Information technology -- Security +techniques -- Lightweight cryptography -- Part 1: General

+ +

https://www.iso.org/standard/56425.html

+ +

 

+ +

[MQTT NIST]

+ +

MQTT supplemental publication, MQTT and the NIST Framework +for Improving Critical Infrastructure Cybersecurity

+ +

http://docs.oasis-open.org/mqtt/mqtt-nist-cybersecurity/v1.0/mqtt-nist-cybersecurity-v1.0.html

+ +

 

+ +

[MQTTV311]

+ +

MQTT V3.1.1 Protocol Specification

+ +

http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html

+ +

 

+ +

[ISO20922]

+ +

MQTT V3.1.1 +ISO Standard (ISO/IEC 20922:2016)

+ +

https://www.iso.org/standard/69466.html

+ +

 

+ +

[NISTCSF]

+ +

Improving Critical Infrastructure Cybersecurity Executive +Order 13636

+ +

https://www.nist.gov/sites/default/files/documents/itl/preliminary-cybersecurity-framework.pdf

+ +

 

+ +

[NIST7628]

+ +

NISTIR 7628 Guidelines for Smart Grid Cyber Security Catalogue

+ +

https://www.nist.gov/sites/default/files/documents/smartgrid/nistir-7628_total.pdf

+ +

 

+ +

[NSAB]

+ +

NSA Suite B Cryptography

+ +

http://www.nsa.gov/ia/programs/suiteb_cryptography/

+ +

 

+ +

[PCIDSS]

+ +

PCI-DSS Payment Card Industry Data Security Standard

+ +

https://www.pcisecuritystandards.org/pci_security/

+ +

 

+ +

[RFC1928]

+ +

Leech, M., Ganis, M., Lee, Y., Kuris, R., Koblas, D., and L. +Jones, "SOCKS Protocol Version 5", RFC 1928, DOI 10.17487/RFC1928, +March 1996,

+ +

http://www.rfc-editor.org/info/rfc1928

+ +

 

+ +

[RFC4511]

+ +

Sermersheim, J., Ed., "Lightweight Directory Access +Protocol (LDAP): The Protocol", RFC 4511, DOI 10.17487/RFC4511, June 2006, +

+ +

http://www.rfc-editor.org/info/rfc4511

+ +

 

+ +

[RFC5280]

+ +

Cooper, D., Santesson, S., Farrell, S., Boeyen, S., Housley, +R., and W. Polk, "Internet X.509 Public Key Infrastructure Certificate and +Certificate Revocation List (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, +May 2008,

+ +

http://www.rfc-editor.org/info/rfc5280

+ +

 

+ +

[RFC6066]

+ +

Eastlake 3rd, D., "Transport Layer Security (TLS) +Extensions: Extension Definitions", RFC 6066, DOI 10.17487/RFC6066, +January 2011,

+ +

http://www.rfc-editor.org/info/rfc6066

+ +

 

+ +

[RFC6749]

+ +

Hardt, D., Ed., "The OAuth 2.0 Authorization +Framework", RFC 6749, DOI 10.17487/RFC6749, October 2012,

+ +

http://www.rfc-editor.org/info/rfc6749

+ +

 

+ +

[RFC6960]

+ +

Santesson, S., Myers, M., Ankney, R., Malpani, A., Galperin, +S., and C. Adams, "X.509 Internet Public Key Infrastructure Online +Certificate Status Protocol - OCSP", RFC 6960, DOI 10.17487/RFC6960, June +2013,

+ +

http://www.rfc-editor.org/info/rfc6960

+ +

 

+ +

[SARBANES]

+ +

Sarbanes-Oxley Act of 2002.

+ +

http://www.gpo.gov/fdsys/pkg/PLAW-107publ204/html/PLAW-107publ204.htm

+ +

 

+ +

[USEUPRIVSH]

+ +

U.S.-EU Privacy Shield Framework

+ +

https://www.privacyshield.gov

+ +

 

+ +

[RFC3986]

+ +

Berners-Lee, T., Fielding, R., and L. Masinter, +"Uniform Resource Identifier (URI): Generic Syntax", STD 66, RFC +3986, DOI 10.17487/RFC3986, January 2005,

+ +

http://www.rfc-editor.org/info/rfc3986

+ +

 

+ +

[RFC1035]

+ +

Mockapetris, P., "Domain names - implementation and +specification", STD 13, RFC 1035, DOI 10.17487/RFC1035, November 1987,

+ +

http://www.rfc-editor.org/info/rfc1035

+ +

 

+ +

[RFC2782]

+ +

Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR +for specifying the location of services (DNS SRV)", RFC 2782, DOI +10.17487/RFC2782, February 2000,

+ +

http://www.rfc-editor.org/info/rfc2782

+ +

 

+ +

1.5 Data representation

+ +

1.5.1 Bits

+ +

Bits in a byte are labelled 7 to 0. Bit number 7 is the most +significant bit, the least significant bit is assigned bit number 0.

+ +

 

+ +

1.5.2 Two Byte Integer

+ +

Two Byte Integer data values are 16-bit unsigned integers in +big-endian order: the high order byte precedes the lower order byte. This means +that a 16-bit word is presented on the network as Most Significant Byte (MSB), +followed by Least Significant Byte (LSB).

+ +

 

+ +

1.5.3 Four Byte Integer

+ +

Four Byte Integer data values are 32-bit unsigned integers +in big-endian order: the high order byte precedes the successively lower order +bytes. This means that a 32-bit word is presented on the network as Most +Significant Byte (MSB), followed by the next most Significant Byte (MSB), +followed by the next most Significant Byte (MSB), followed by Least Significant +Byte (LSB).

+ +

 

+ +

1.5.4 UTF-8 Encoded String

+ +

Text fields within the MQTT Control Packets described later +are encoded as UTF-8 strings. UTF-8 [RFC3629] is an +efficient encoding of Unicode [Unicode] characters that +optimizes the encoding of ASCII characters in support of text-based +communications.

+ +

 

+ +

Each of these strings is prefixed with a Two Byte Integer +length field that gives the number of bytes in a UTF-8 encoded string itself, +as illustrated in Figure 1.1 Structure of UTF-8 Encoded +Strings below. Consequently, the maximum size of a UTF-8 Encoded String is +65,535 bytes.

+ +

 

+ +

Unless stated otherwise all UTF-8 +encoded strings can have any length in the range 0 to 65,535 bytes.

+ +

 

+ +

Figure +1‑1 Structure of UTF-8 Encoded Strings

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

String length MSB

+
+

byte 2

+
+

String length LSB

+
+

byte 3 ….

+
+

UTF-8 encoded + character data, if length > 0.

+
+ +

 

+ +

The character data in a +UTF-8 Encoded String MUST be well-formed UTF-8 as defined by the Unicode +specification [Unicode] and restated in RFC 3629 [RFC3629]. +In particular, the character data MUST NOT include encodings of code points +between U+D800 and U+DFFF [MQTT-1.5.4-1]. If the Client or Server +receives an MQTT Control Packet containing ill-formed UTF-8 it is a Malformed +Packet. Refer to section 4.13 for information about handling errors.

+ +

 

+ +

A UTF-8 Encoded String MUST +NOT include an encoding of the null character U+0000. [MQTT-1.5.4-2]. If a receiver (Server or Client) +receives an MQTT Control Packet containing U+0000 it is a Malformed Packet. +Refer to section 4.13 for information about +handling errors.

+ +

 

+ +

The data SHOULD NOT include encodings of the Unicode +[Unicode] code points listed below. If a receiver (Server or Client) receives an +MQTT Control Packet containing any of them it MAY treat it as a Malformed Packet. +These are the Disallowed Unicode code points. Refer +to section 5.4.9 for more information +about handling Disallowed Unicode code points.

+ +

 

+ +

·         +U+0001..U+001F control characters

+ +

·         +U+007F..U+009F control characters

+ +

·         +Code points defined in the Unicode specification [Unicode] to be non-characters (for example U+0FFFF)

+ +

 

+ +

A UTF-8 encoded sequence +0xEF 0xBB 0xBF is always interpreted as U+FEFF ("ZERO WIDTH NO-BREAK SPACE") +wherever it appears in a string and MUST NOT be skipped over or stripped off by +a packet receiver [MQTT-1.5.4-3].

+ +

 

+ +

Non-normative example

+ +

For example, +the string A𪛔 +which is LATIN +CAPITAL Letter A followed by the code point U+2A6D4 (which represents a CJK +IDEOGRAPH EXTENSION B character) is encoded as follows:

+ +

 

+ +

Figure +1‑2 UTF-8 Encoded String non-normative example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

String Length MSB + (0x00)

+
+

 

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

String Length LSB + (0x05)

+
+

 

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

byte 3

+
+

‘A’ (0x41)

+
+

 

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 4

+
+

(0xF0)

+
+

 

+
+

1

+
+

1

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 5

+
+

(0xAA)

+
+

 

+
+

1

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

byte 6

+
+

(0x9B)

+
+

 

+
+

1

+
+

0

+
+

0

+
+

1

+
+

1

+
+

0

+
+

1

+
+

1

+
+

byte 7

+
+

(0x94)

+
+

 

+
+

1

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+ +

 

+ +

1.5.5 Variable Byte Integer

+ +

The Variable Byte Integer is encoded using an encoding +scheme which uses a single byte for values up to 127. Larger values are handled +as follows. The least significant seven bits of each byte encode the data, and +the most significant bit is used to indicate whether there are bytes following +in the representation. Thus, each byte encodes 128 values and a +"continuation bit". The maximum number of bytes in the Variable Byte +Integer field is four. The encoded value MUST +use the minimum number of bytes necessary to represent the value [MQTT-1.5.5-1]. This is +shown in Table 1‑1 Size of Variable Byte Integer.

+ +

 

+ +

Table 1‑1 +Size of Variable Byte Integer

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Digits

+
+

From

+
+

To

+
+

1

+
+

0 (0x00)

+
+

127 (0x7F)

+
+

2

+
+

128 (0x80, 0x01)

+
+

16,383 (0xFF, 0x7F)

+
+

3

+
+

16,384 (0x80, 0x80, 0x01)

+
+

2,097,151 (0xFF, 0xFF, 0x7F)

+
+

4

+
+

2,097,152 (0x80, 0x80, 0x80, + 0x01)

+
+

268,435,455 (0xFF, 0xFF, 0xFF, + 0x7F)

+
+ +

 

+ +

Non-normative +comment

+ +

The algorithm +for encoding a non-negative integer (X) into the Variable Byte Integer encoding +scheme is as follows:

+ +

 

+ +

do

+ +

   encodedByte += X MOD 128

+ +

   X += X DIV 128

+ +

   // +if there are more data to encode, set the top bit of this byte

+ +

   if +(X > 0)

+ +

      encodedByte += encodedByte OR 128

+ +

   endif

+ +

   'output' +encodedByte

+ +

while +(X > 0)

+ +

 

+ +

Where MOD is the modulo operator (% in C), DIV is integer division (/ in C), and OR is bit-wise or (| in C).

+ +

 

+ +

Non-normative +comment

+ +

The algorithm +for decoding a Variable Byte Integer type is as follows:

+ +

  

+ +

multiplier += 1

+ +

value += 0

+ +

do

+ +

   encodedByte += 'next byte from stream'

+ +

   value ++= (encodedByte AND 127) * multiplier

+ +

   if +(multiplier > 128*128*128)

+ +

      throw +Error(Malformed Variable Byte Integer)

+ +

   multiplier +*= 128

+ +

while +((encodedByte AND 128) != 0)

+ +

 

+ +

where AND is the bit-wise and +operator (& in C).

+ +

 

+ +

When this algorithm terminates, value contains the Variable +Byte Integer value.

+ +

 

+ +

1.5.6 +Binary Data

+ +

Binary Data is represented by a Two Byte Integer length +which indicates the number of data bytes, followed by that number of bytes. Thus, +the length of Binary Data is limited to the range of 0 to 65,535 Bytes.

+ +

 

+ +

1.5.7 +UTF-8 String Pair

+ +

A UTF-8 String Pair consists of two UTF-8 Encoded Strings. +This data type is used to hold name-value pairs. The first string serves as the +name, and the second string contains the value.

+ +

 

+ +

Both strings MUST comply +with the requirements for UTF-8 Encoded Strings [MQTT-1.5.7-1]. +If a receiver (Client or Server) receives a string pair which does not meet +these requirements it is a Malformed Packet. Refer to section +4.13 for information about handling errors.

+ +

 

+ +

1.6 Security

+ +

MQTT Client and Server +implementations SHOULD offer Authentication, Authorization and secure +communication options, such as those discussed in Chapter 5. Applications +concerned with critical infrastructure, personally identifiable information, or +other personal or sensitive information are strongly advised to use these +security capabilities.

+ +

 

+ +

1.7 Editing convention

+ +

Text highlighted in Yellow +within this specification identifies conformance statements. Each conformance +statement has been assigned a reference in the format +[MQTT-x.x.x-y] where +x.x.x is the +section number and y is a statement counter within the section.

+ +

 

+ +

1.8 Change history

+ +

1.8.1 MQTT v3.1.1

+ +

MQTT v3.1.1 was the first OASIS standard version of MQTT [MQTTV311].

+ +

MQTT v3.1.1 is also standardized as ISO/IEC 20922:2016 [ISO20922].

+ +

 

+ +

1.8.2 MQTT v5.0

+ +

MQTT v5.0 adds a significant number of new features to MQTT +while keeping much of the core in place. The major functional objectives are:

+ +

·         +Enhancements for scalability and large scale systems

+ +

·         +Improved error reporting

+ +

·         +Formalize common patterns including capability discovery and +request response

+ +

·         +Extensibility mechanisms including user properties

+ +

·         +Performance improvements and support for small clients

+ +

 

+ +

Refer to Appendix C for a summary +of changes in MQTT v5.0.

+ +

 

+ +
+ +

2      MQTT +Control Packet format

+ +
+ +

2.1 Structure of an MQTT +Control Packet

+ +

The MQTT protocol operates by exchanging a series of MQTT +Control Packets in a defined way. This section describes the format of these +packets.

+ +

 

+ +

An MQTT Control Packet consists of up to three parts, always +in the following order as shown below.

+ +

 

+ +

Figure 2‑1 +Structure of an MQTT Control Packet

+ + + + + + + + + + + +
+

Fixed Header, + present in all MQTT Control Packets

+
+

Variable Header, + present in some MQTT Control Packets

+
+

Payload, present in + some MQTT Control Packets

+
+ +

 

+ +

2.1.1 Fixed Header

+ +

Each MQTT Control Packet contains a Fixed Header as shown +below.

+ +

 

+ +

Figure +2‑2 Fixed Header format

+ + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type

+
+

Flags specific to + each MQTT Control Packet type

+
+

byte 2…

+
+

Remaining Length

+
+ +

 

+ +

2.1.2 MQTT Control Packet type

+ +

Position: byte 1, bits 7-4.

+ +

Represented as a 4-bit unsigned value, the values are shown +below.

+ +

 

+ +

Table 2‑1 MQTT Control Packet types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Name

+
+

Value

+
+

Direction of + flow

+
+

Description

+
+

Reserved

+
+

0

+
+

Forbidden

+
+

Reserved

+
+

CONNECT

+
+

1

+
+

Client to Server

+
+

Connection request

+
+

CONNACK

+
+

2

+
+

Server to Client

+
+

Connect acknowledgment

+
+

PUBLISH

+
+

3

+
+

Client to Server or

+

Server to Client

+
+

Publish message

+
+

PUBACK

+
+

4

+
+

Client to Server or

+

Server to Client

+
+

Publish acknowledgment (QoS 1)

+
+

PUBREC

+
+

5

+
+

Client to Server or

+

Server to Client

+
+

Publish received (QoS 2 delivery part 1)

+
+

PUBREL

+
+

6

+
+

Client to Server or

+

Server to Client

+
+

Publish release (QoS 2 delivery part 2)

+
+

PUBCOMP

+
+

7

+
+

Client to Server or

+

Server to Client

+
+

Publish complete (QoS 2 delivery part 3)

+
+

SUBSCRIBE

+
+

8

+
+

Client to Server

+
+

Subscribe request

+
+

SUBACK

+
+

9

+
+

Server to Client

+
+

Subscribe acknowledgment

+
+

UNSUBSCRIBE

+
+

10

+
+

Client to Server

+
+

Unsubscribe request

+
+

UNSUBACK

+
+

11

+
+

Server to Client

+
+

Unsubscribe acknowledgment

+
+

PINGREQ

+
+

12

+
+

Client to Server

+
+

PING request

+
+

PINGRESP

+
+

13

+
+

Server to Client

+
+

PING response

+
+

DISCONNECT

+
+

14

+
+

Client to Server or

+

Server to Client

+
+

Disconnect notification

+
+

AUTH

+
+

15

+
+

Client to Server or + Server to Client

+
+

Authentication exchange

+
+ +

 

+ +

2.1.3 Flags

+ +

The remaining bits [3-0] of byte 1 in the Fixed Header +contain flags specific to each MQTT Control Packet type as shown below. Where a flag bit is +marked as “Reserved”, it is reserved for future use and MUST be set to the +value listed [MQTT-2.1.3-1]. If invalid +flags are received it is a Malformed Packet. Refer to section 4.13 for details about handling errors.

+ +

 

+ +

Table +2‑2 Flag Bits

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

MQTT Control + Packet

+
+

Fixed Header + flags

+
+

Bit 3

+
+

Bit 2

+
+

Bit 1

+
+

Bit 0

+
+

CONNECT

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

CONNACK

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

PUBLISH

+
+

Used in MQTT v5.0

+
+

DUP

+
+

QoS

+
+

RETAIN

+
+

PUBACK

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

PUBREC

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

PUBREL

+
+

Reserved

+
+

0

+
+

0

+
+

1

+
+

0

+
+

PUBCOMP

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

SUBSCRIBE

+
+

Reserved

+
+

0

+
+

0

+
+

1

+
+

0

+
+

SUBACK

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

UNSUBSCRIBE

+
+

Reserved

+
+

0

+
+

0

+
+

1

+
+

0

+
+

UNSUBACK

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

PINGREQ

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

PINGRESP

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

DISCONNECT

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+

AUTH

+
+

Reserved

+
+

0

+
+

0

+
+

0

+
+

0

+
+ +

 

+ +

DUP = Duplicate delivery of a PUBLISH packet

+ +

QoS = PUBLISH Quality of Service

+ +

RETAIN = PUBLISH retained message flag

+ +

Refer to section 3.3.1 +for a description of the DUP, QoS, and RETAIN flags in the PUBLISH packet.

+ +

 

+ +

2.1.4 Remaining Length

+ +

Position: starts at byte +2.

+ +

 

+ +

The Remaining Length is a Variable Byte Integer that +represents the number of bytes remaining within the current Control Packet, +including data in the Variable Header and the Payload. The Remaining Length +does not include the bytes used to encode the Remaining Length. The packet size is the total number of bytes in an MQTT Control +Packet, this is equal to the length of the Fixed Header plus the Remaining +Length.

+ +

 

+ +

2.2 Variable Header

+ +

Some types of MQTT Control Packet contain a Variable Header +component. It resides between the Fixed Header and the Payload. The content of +the Variable Header varies depending on the packet type. The Packet Identifier +field of Variable Header is common in several packet types.

+ +

 

+ +

2.2.1 Packet +Identifier

+ +

The Variable Header component of +many of the MQTT Control Packet types includes a Two Byte Integer Packet +Identifier field. These MQTT Control Packets are PUBLISH (where QoS > 0), +PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK.

+ +

 

+ +

MQTT Control Packets that require a Packet Identifier are shown +below:

+ +

 

+ +

Table 2‑3 MQTT Control Packets that contain a Packet +Identifier

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

MQTT Control Packet

+
+

Packet Identifier field

+
+

CONNECT

+
+

NO

+
+

CONNACK

+
+

NO

+
+

PUBLISH

+
+

YES (If QoS > 0)

+
+

PUBACK

+
+

YES

+
+

PUBREC

+
+

YES

+
+

PUBREL

+
+

YES

+
+

PUBCOMP

+
+

YES

+
+

SUBSCRIBE

+
+

YES

+
+

SUBACK

+
+

YES

+
+

UNSUBSCRIBE

+
+

YES

+
+

UNSUBACK

+
+

YES

+
+

PINGREQ

+
+

NO

+
+

PINGRESP

+
+

NO

+
+

DISCONNECT

+
+

NO

+
+

AUTH

+
+

NO

+
+ +

 

+ +

A PUBLISH packet MUST NOT +contain a Packet Identifier if its QoS value is set to 0 [MQTT-2.2.1-2].

+ +

 

+ +

Each time a Client sends a +new SUBSCRIBE, UNSUBSCRIBE,or PUBLISH (where QoS > 0) MQTT Control Packet it +MUST assign it a non-zero Packet Identifier that is currently unused [MQTT-2.2.1-3].

+ +

 

+ +

Each time a Server sends a +new PUBLISH (with QoS > 0) MQTT Control Packet it MUST assign it a non zero +Packet Identifier that is currently unused [MQTT-2.2.1-4]. +

+ +

 

+ +

The Packet Identifier becomes available for reuse after the sender +has processed the corresponding acknowledgement packet, defined as follows. In +the case of a QoS 1 PUBLISH, this is the corresponding PUBACK; in the case of +QoS 2 PUBLISH it is PUBCOMP or a PUBREC with a Reason Code of 128 or greater. +For SUBSCRIBE or UNSUBSCRIBE it is the corresponding SUBACK or UNSUBACK.

+ +

 

+ +

Packet Identifiers used with PUBLISH, SUBSCRIBE and +UNSUBSCRIBE packets form a single, unified set of identifiers separately for +the Client and the Server in a Session. A Packet Identifier cannot be used by +more than one command at any time.

+ +

 

+ +

A PUBACK, PUBREC , PUBREL, +or PUBCOMP packet MUST contain the same Packet Identifier as the PUBLISH packet +that was originally sent [MQTT-2.2.1-5]. A SUBACK and UNSUBACK MUST contain the Packet +Identifier that was used in the corresponding SUBSCRIBE and UNSUBSCRIBE packet respectively +[MQTT-2.2.1-6].

+ +

 

+ +

The Client and Server assign Packet Identifiers +independently of each other. As a result, Client-Server pairs can participate +in concurrent message exchanges using the same Packet Identifiers.

+ +

 

+ +

Non-normative +comment

+ +

It is possible for a Client to send +a PUBLISH packet with Packet Identifier 0x1234 and then receive a different +PUBLISH packet with Packet Identifier 0x1234 from its Server before it receives +a PUBACK for the PUBLISH packet that it sent.

+ +

 

+ +

 Client   +                                                + Server

+ +

PUBLISH Packet Identifier=0x1234 ‒→

+ +

                                    + +                  +←‒ PUBLISH Packet +Identifier=0x1234

+ +

PUBACK Packet +Identifier=0x1234 ‒→

+ +

                                    +   +          +     ←‒ PUBACK +Packet Identifier=0x1234

+ +

 

+ +

 

+ +

2.2.2 Properties

+ +

The last field in the Variable Header of the CONNECT, CONNACK, +PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, +UNSUBACK, DISCONNECT, and AUTH packet is a set of Properties. In the CONNECT +packet there is also an optional set of Properties in the Will Properties field +with the Payload.

+ +

 

+ +

The set of Properties is composed of a Property Length followed +by the Properties.

+ +

 

+ +

2.2.2.1 Property Length

+ +

The Property Length is encoded as a Variable Byte Integer. +The Property Length does not include the bytes used to encode itself, but +includes the length of the Properties. If there +are no properties, this MUST be indicated by including a Property Length of +zero [MQTT-2.2.2-1].

+ +

 

+ +

2.2.2.2 Property

+ +

A Property consists of an Identifier which defines its usage +and data type, followed by a value. The Identifier is encoded as a Variable +Byte Integer. A Control Packet which contains an Identifier which is not valid +for its packet type, or contains a value not of the specified data type, is a +Malformed Packet. If received, use a CONNACK or DISCONNECT packet with Reason +Code 0x81 (Malformed Packet) as described in section +4.13 Handling errors. There is no significance in the order of Properties +with different Identifiers.

+ +

 

+ +

Table 2‑4 +- Properties

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Identifier

+
+

Name (usage)

+
+

Type

+
+

Packet / Will Properties

+

 

+
+

Dec

+
+

Hex

+
+

1

+
+

0x01

+
+

Payload Format Indicator

+
+

Byte

+
+

PUBLISH, Will Properties

+
+

2

+
+

0x02

+
+

Message Expiry Interval

+
+

Four Byte Integer

+
+

PUBLISH, Will Properties

+
+

3

+
+

0x03

+
+

Content Type

+
+

UTF-8 Encoded String

+
+

PUBLISH, Will Properties

+
+

8

+
+

0x08

+
+

Response Topic

+
+

UTF-8 Encoded String

+
+

PUBLISH, Will Properties

+
+

9

+
+

0x09

+
+

Correlation Data

+
+

Binary Data

+
+

PUBLISH, Will Properties

+
+

11

+
+

0x0B

+
+

Subscription Identifier

+
+

Variable Byte Integer

+
+

PUBLISH, SUBSCRIBE

+
+

17

+
+

0x11

+
+

Session Expiry Interval

+
+

Four Byte Integer

+
+

CONNECT, CONNACK, DISCONNECT

+
+

18

+
+

0x12

+
+

Assigned Client Identifier

+
+

UTF-8 Encoded String

+
+

CONNACK

+
+

19

+
+

0x13

+
+

Server Keep Alive

+
+

Two Byte Integer

+
+

CONNACK

+
+

21

+
+

0x15

+
+

Authentication Method

+
+

UTF-8 Encoded String

+
+

CONNECT, CONNACK, AUTH

+
+

22

+
+

0x16

+
+

Authentication Data

+
+

Binary Data

+
+

CONNECT, CONNACK, AUTH

+
+

23

+
+

0x17

+
+

Request Problem Information

+
+

Byte

+
+

CONNECT

+
+

24

+
+

0x18

+
+

Will Delay Interval

+
+

Four Byte Integer

+
+

Will Properties

+
+

25

+
+

0x19

+
+

Request Response Information

+
+

Byte

+
+

CONNECT

+
+

26

+
+

0x1A

+
+

Response Information

+
+

UTF-8 Encoded String

+
+

CONNACK

+
+

28

+
+

0x1C

+
+

Server Reference

+
+

UTF-8 Encoded String

+
+

CONNACK, DISCONNECT

+
+

31

+
+

0x1F

+
+

Reason String

+
+

UTF-8 Encoded String

+
+

CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, + UNSUBACK, DISCONNECT, AUTH

+
+

33

+
+

0x21

+
+

Receive Maximum

+
+

Two Byte Integer

+
+

CONNECT, CONNACK

+
+

34

+
+

0x22

+
+

Topic Alias Maximum

+
+

Two Byte Integer

+
+

CONNECT, CONNACK

+
+

35

+
+

0x23

+
+

Topic Alias

+
+

Two Byte Integer

+
+

PUBLISH

+
+

36

+
+

0x24

+
+

Maximum QoS

+
+

Byte

+
+

CONNACK

+
+

37

+
+

0x25

+
+

Retain Available

+
+

Byte

+
+

CONNACK

+
+

38

+
+

0x26

+
+

User Property

+
+

UTF-8 String Pair

+
+

CONNECT, CONNACK, PUBLISH, Will Properties, PUBACK, + PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, + DISCONNECT, AUTH

+
+

39

+
+

0x27

+
+

Maximum Packet Size

+
+

Four Byte Integer

+
+

CONNECT, CONNACK

+
+

40

+
+

0x28

+
+

Wildcard Subscription Available

+
+

Byte

+
+

CONNACK

+
+

41

+
+

0x29

+
+

Subscription Identifier Available

+
+

Byte

+
+

CONNACK

+
+

42

+
+

0x2A

+
+

Shared Subscription Available

+
+

Byte

+
+

CONNACK

+
+ +

 

+ +

Non-normative comment

+ +

Although the Property Identifier is +defined as a Variable Byte Integer, in this version of the specification all of +the Property Identifiers are one byte long.

+ +

 

+ +

2.3 Payload

+ +

Some MQTT Control Packets contain a Payload as the final +part of the packet. In the PUBLISH packet this is the Application Message

+ +

 

+ +

Table +2‑5 - MQTT Control Packets that contain a Payload

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

MQTT Control Packet

+
+

Payload

+
+

CONNECT

+
+

Required

+
+

CONNACK

+
+

None

+
+

PUBLISH

+
+

Optional

+
+

PUBACK

+
+

None

+
+

PUBREC

+
+

None

+
+

PUBREL

+
+

None

+
+

PUBCOMP

+
+

None

+
+

SUBSCRIBE

+
+

Required

+
+

SUBACK

+
+

Required

+
+

UNSUBSCRIBE

+
+

Required

+
+

UNSUBACK

+
+

Required

+
+

PINGREQ

+
+

None

+
+

PINGRESP

+
+

None

+
+

DISCONNECT

+
+

None

+
+

AUTH

+
+

None

+
+ +

 

+ +

2.4 Reason Code

+ +

A Reason Code is a one byte unsigned value that indicates +the result of an operation. Reason Codes less than 0x80 indicate successful +completion of an operation. The normal Reason Code for success is 0. Reason +Code values of 0x80 or greater indicate failure.

+ +

 

+ +

The CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, DISCONNECT and +AUTH Control Packets have a single Reason Code as part of the Variable Header. +The SUBACK and UNSUBACK packets contain a list of one or more Reason Codes in +the Payload.

+ +

 

+ +

The Reason Codes share a common set of values as shown +below.

+ +

 

+ +

Table +2‑6 - Reason Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Reason Code

+
+

Name

+
+

Packets

+

 

+
+

Decimal

+
+

Hex

+
+

0

+
+

0x00

+
+

Success

+
+

CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, UNSUBACK, AUTH

+
+

0

+
+

0x00

+
+

Normal disconnection

+
+

DISCONNECT

+
+

0

+
+

0x00

+
+

Granted QoS 0

+
+

SUBACK

+
+

1

+
+

0x01

+
+

Granted QoS 1

+
+

SUBACK

+
+

2

+
+

0x02

+
+

Granted QoS 2

+
+

SUBACK

+
+

4

+
+

0x04

+
+

Disconnect with Will Message

+
+

DISCONNECT

+
+

16

+
+

0x10

+
+

No matching subscribers

+
+

PUBACK, PUBREC

+
+

17

+
+

0x11

+
+

No subscription existed

+
+

UNSUBACK

+
+

24

+
+

0x18

+
+

Continue authentication

+
+

AUTH

+
+

25

+
+

0x19

+
+

Re-authenticate

+
+

AUTH

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT

+
+

129

+
+

0x81

+
+

Malformed Packet

+
+

CONNACK, DISCONNECT

+
+

130

+
+

0x82

+
+

Protocol Error

+
+

CONNACK, DISCONNECT

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT

+
+

132

+
+

0x84

+
+

Unsupported Protocol Version

+
+

CONNACK

+
+

133

+
+

0x85

+
+

Client Identifier not valid

+
+

CONNACK

+
+

134

+
+

0x86

+
+

Bad User Name or Password

+
+

CONNACK

+
+

135

+
+

0x87

+
+

Not authorized

+
+

CONNACK, PUBACK, PUBREC, SUBACK, UNSUBACK, DISCONNECT

+
+

136

+
+

0x88

+
+

Server unavailable

+
+

CONNACK

+
+

137

+
+

0x89

+
+

Server busy

+
+

CONNACK, DISCONNECT

+
+

138

+
+

0x8A

+
+

Banned

+
+

CONNACK

+
+

139

+
+

0x8B

+
+

Server shutting down

+
+

DISCONNECT

+
+

140

+
+

0x8C

+
+

Bad authentication method

+
+

CONNACK, DISCONNECT

+
+

141

+
+

0x8D

+
+

Keep Alive timeout

+
+

DISCONNECT

+
+

142

+
+

0x8E

+
+

Session taken over

+
+

DISCONNECT

+
+

143

+
+

0x8F

+
+

Topic Filter invalid

+
+

SUBACK, UNSUBACK, DISCONNECT

+
+

144

+
+

0x90

+
+

Topic Name invalid

+
+

CONNACK, PUBACK, PUBREC, DISCONNECT

+
+

145

+
+

0x91

+
+

Packet Identifier in use

+
+

PUBACK, PUBREC, SUBACK, UNSUBACK

+
+

146

+
+

0x92

+
+

Packet Identifier not found

+
+

PUBREL, PUBCOMP

+
+

147

+
+

0x93

+
+

Receive Maximum exceeded

+
+

DISCONNECT

+
+

148

+
+

0x94

+
+

Topic Alias invalid

+
+

DISCONNECT

+
+

149

+
+

0x95

+
+

Packet too large

+
+

CONNACK, DISCONNECT

+
+

150

+
+

0x96

+
+

Message rate too high

+
+

DISCONNECT

+
+

151

+
+

0x97

+
+

Quota exceeded

+
+

CONNACK, PUBACK, PUBREC, SUBACK, DISCONNECT

+
+

152

+
+

0x98

+
+

Administrative action

+
+

DISCONNECT

+
+

153

+
+

0x99

+
+

Payload format invalid

+
+

CONNACK, PUBACK, PUBREC, DISCONNECT

+
+

154

+
+

0x9A

+
+

Retain not supported

+
+

CONNACK, DISCONNECT

+
+

155

+
+

0x9B

+
+

QoS not supported

+
+

CONNACK, DISCONNECT

+
+

156

+
+

0x9C

+
+

Use another server

+
+

CONNACK, DISCONNECT

+
+

157

+
+

0x9D

+
+

Server moved

+
+

CONNACK, DISCONNECT

+
+

158

+
+

0x9E

+
+

Shared Subscriptions not supported

+
+

SUBACK, DISCONNECT

+
+

159

+
+

0x9F

+
+

Connection rate exceeded

+
+

CONNACK, DISCONNECT

+
+

160

+
+

0xA0

+
+

Maximum connect time

+
+

DISCONNECT

+
+

161

+
+

0xA1

+
+

Subscription Identifiers not supported

+
+

SUBACK, DISCONNECT

+
+

162

+
+

0xA2

+
+

Wildcard Subscriptions not supported

+
+

SUBACK, DISCONNECT

+
+ +

 

+ +

Non-normative comment

+ +

For Reason Code 0x91 (Packet +identifier in use), the response to this is either to try to fix the state, or +to reset the Session state by connecting using Clean Start set to 1, or to +decide if the Client or Server implementations are defective.

+ +

 

+ +
+ +

3      MQTT +Control Packets

+ +
+ +

 

+ +

3.1 CONNECT – Connection Request

+ +

After a Network Connection +is established by a Client to a Server, the first packet sent from the Client to +the Server MUST be a CONNECT packet [MQTT-3.1.0-1].

+ +

 

+ +

A Client can only send the CONNECT packet once over a +Network Connection. The Server MUST process a +second CONNECT packet sent from a Client as a Protocol Error and close the +Network Connection [MQTT-3.1.0-2]. Refer to +section 4.13 for information about handling errors.

+ +

 

+ +

The Payload contains one or more +encoded fields. They specify a unique Client identifier for the Client, a Will Topic, +Will Payload, User Name and Password. All but the Client identifier can be +omitted and their presence is determined based on flags in the Variable Header.

+ +

 

+ +

3.1.1 CONNECT Fixed Header

+ +

Figure 3‑1 +- CONNECT packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (1)

+
+

Reserved

+
+

 

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2…

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable Header plus the length of +the Payload. It is encoded as a Variable Byte Integer.

+ +

 

+ +

3.1.2 CONNECT Variable Header

+ +

The Variable Header for the CONNECT Packet contains the following +fields in this order: Protocol Name, Protocol Level, Connect Flags, Keep Alive, +and Properties. The rules for encoding Properties are described in section 2.2.2.

+ +

 

+ +

3.1.2.1 Protocol Name

+ +

Figure 3‑2 +- Protocol Name bytes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Protocol Name

+
+

byte 1

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Length LSB (4)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

byte 3

+
+

‘M’

+
+

0

+
+

1

+
+

0

+
+

0

+
+

1

+
+

1

+
+

0

+
+

1

+
+

byte 4

+
+

‘Q’

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 5

+
+

‘T’

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

byte 6

+
+

‘T’

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+ +

 

+ +

The Protocol Name is a UTF-8 +Encoded String that represents the protocol name “MQTT”, capitalized as shown. +The string, its offset and length will not be changed by future versions of the +MQTT specification.

+ +

 

+ +

A Server which support multiple protocols uses the Protocol +Name to determine whether the data is MQTT. The +protocol name MUST be the UTF-8 String "MQTT". If the Server does not +want to accept the CONNECT, and wishes to reveal that it is an MQTT Server it +MAY send a CONNACK packet with Reason Code of 0x84 (Unsupported Protocol +Version), and then it MUST close the Network Connection [MQTT-3.1.2-1].

+ +

 

+ +

Non-normative +comment

+ +

Packet +inspectors, such as firewalls, could use the Protocol Name to identify MQTT +traffic.

+ +

 

+ +

3.1.2.2 Protocol Version

+ +

Figure 3‑3 +- Protocol Version byte

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Protocol Level

+
+

byte 7

+
+

Version(5)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+ +

 

+ +

The one byte unsigned value that represents the revision +level of the protocol used by the Client. The value of the Protocol Version +field for version 5.0 of the protocol is 5 (0x05).

+ +

 

+ +

A Server which supports multiple versions of the MQTT +protocol uses the Protocol Version to determine which version of MQTT the +Client is using. If the Protocol Version is not +5 and the Server does not want to accept the CONNECT packet, the Server MAY +send a CONNACK packet with Reason Code +0x84 (Unsupported Protocol Version) and then MUST close the Network Connection +[MQTT-3.1.2-2].

+ +

 

+ +

3.1.2.3 Connect Flags

+ +

The Connect Flags byte contains several parameters +specifying the behavior of the MQTT connection. It also indicates the presence +or absence of fields in the Payload.

+ +

Figure 3‑4 +- Connect Flag bits

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

 

+
+

User Name Flag

+
+

Password Flag

+
+

Will Retain

+
+

Will QoS

+
+

Will Flag

+
+

Clean Start

+
+

Reserved

+
+

byte 8

+
+

X

+
+

X

+
+

X

+
+

X

+
+

X

+
+

X

+
+

X

+
+

0

+
+ +

The Server MUST validate +that the reserved flag in the CONNECT packet is set to 0 [MQTT-3.1.2-3]. If the reserved flag is not 0 it is a +Malformed Packet. Refer to section 4.13 for +information about handling errors.

+ +

 

+ +

3.1.2.4 +Clean Start

+ +

Position: bit 1 of the +Connect Flags byte.

+ +

 

+ +

This bit specifies whether the Connection starts a new +Session or is a continuation of an existing Session. Refer to section 4.1 for a definition of the Session State.

+ +

 

+ +

If +a CONNECT packet is received with Clean Start is set to 1, the Client and +Server MUST discard any existing Session and start a new Session [MQTT-3.1.2-4]. Consequently, the Session Present flag +in CONNACK is always set to 0 if Clean Start is set to 1.

+ +

 

+ +

If +a CONNECT packet is received with Clean Start set to 0 and there is a Session +associated with the Client Identifier, the Server MUST resume communications +with the Client based on state from the existing Session [MQTT-3.1.2-5]. If a +CONNECT packet is received with Clean Start set to 0 and there is no Session +associated with the Client Identifier, the Server MUST create a new Session +[MQTT-3.1.2-6].

+ +

 

+ +

3.1.2.5 +Will Flag

+ +

Position: bit 2 of the Connect Flags.

+ +

 

+ +

If the Will Flag is set to 1 +this indicates that a Will Message MUST be stored on the Server and associated +with the Session [MQTT-3.1.2-7]. The Will +Message consists of the Will Properties, Will Topic, and Will Payload fields in +the CONNECT Payload. The Will Message MUST be +published after the Network Connection is subsequently closed and either the +Will Delay Interval has elapsed or the Session ends, unless the Will Message +has been deleted by the Server on receipt of a DISCONNECT packet with Reason +Code 0x00 (Normal disconnection) or a new Network Connection for the ClientID +is opened before the Will Delay Interval has elapsed [MQTT-3.1.2-8].

+ +

Situations in which the Will Message is published include, +but are not limited to:

+ + + +

 

+ +

If the Will Flag is set to +1, the Will Properties, Will Topic, and Will Payload fields MUST be present in +the Payload [MQTT-3.1.2-9]. The Will Message MUST be removed from the stored +Session State in the Server once it has been published or the Server has +received a DISCONNECT packet with a Reason Code of 0x00 (Normal disconnection) +from the Client [MQTT-3.1.2-10].

+ +

 

+ +

The Server SHOULD publish Will Messages promptly after the +Network Connection is closed and the Will Delay Interval has passed, or when +the Session ends, whichever occurs first. In the case of a Server shutdown or +failure, the Server MAY defer publication of Will Messages until a subsequent +restart. If this happens, there might be a delay between the time the Server +experienced failure and when the Will Message is published.

+ +

 

+ +

Refer to section 3.1.3.2 +for information about the Will Delay Interval.

+ +

 

+ +

Non-normative comment

+ +

The Client can arrange for the Will +Message to notify that Session Expiry has occurred by setting the Will Delay +Interval to be longer than the Session Expiry Interval and sending DISCONNECT +with Reason Code 0x04 (Disconnect with Will Message).

+ +

 

+ +

3.1.2.6 Will QoS

+ +

Position: bits 4 and 3 of the Connect Flags.

+ +

 

+ +

These two bits specify the QoS level to be used when +publishing the Will Message.

+ +

 

+ +

If the Will Flag is set to 0, +then the Will QoS MUST be set to 0 (0x00) [MQTT-3.1.2-11].

+ +

If the Will Flag is set to +1, the value of Will QoS can be 0 (0x00), 1 (0x01), or 2 (0x02) [MQTT-3.1.2-12]. A +value of 3 (0x03) is a Malformed Packet. Refer to +section 4.13 for information about handling errors.

+ +

 

+ +

3.1.2.7 Will Retain

+ +

Position: bit 5 of the Connect Flags.

+ +

 

+ +

This bit specifies if the Will Message is to be retained +when it is published.

+ +

 

+ +

If the Will Flag is set to +0, then Will Retain MUST be set to 0 [MQTT-3.1.2-13]. If the Will Flag is +set to 1 and Will Retain is set to 0, the Server MUST publish the Will Message +as a non-retained message [MQTT-3.1.2-14]. If the Will Flag is +set to 1 and Will Retain is set to 1, the Server MUST publish the Will Message +as a retained message [MQTT-3.1.2-15].

+ +

 

+ +

3.1.2.8 User Name Flag

+ +

Position: bit 7 of the Connect Flags.

+ +

 

+ +

If the User Name Flag is set +to 0, a User Name MUST NOT be present in the Payload [MQTT-3.1.2-16]. If +the User Name Flag is set to 1, a User Name MUST be present in the Payload +[MQTT-3.1.2-17].

+ +

 

+ +

3.1.2.9 Password Flag

+ +

Position: bit 6 of the Connect Flags.

+ +

 

+ +

If the Password Flag is set +to 0, a Password MUST NOT be present in the Payload [MQTT-3.1.2-18]. If +the Password Flag is set to 1, a Password MUST be present in the Payload [MQTT-3.1.2-19].

+ +

 

+ +

Non-normative comment

+ +

This version of the protocol allows +the sending of a Password with no User Name, where MQTT v3.1.1 did not. This +reflects the common use of Password for credentials other than a password.

+ +

 

+ +

3.1.2.10 +Keep Alive

+ +

Figure 3‑5 +- Keep Alive bytes

+ + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 9

+
+

Keep Alive MSB

+
+

byte 10

+
+

Keep Alive LSB

+
+ +

 

+ +

The Keep Alive is a Two Byte Integer which is a time +interval measured in seconds. It is the maximum time interval that is permitted +to elapse between the point at which the Client finishes transmitting one MQTT Control +Packet and the point it starts sending the next. It is the responsibility of +the Client to ensure that the interval between MQTT Control Packets being sent +does not exceed the Keep Alive value. If Keep +Alive is non-zero and in the absence of sending any other MQTT Control Packets, +the Client MUST send a PINGREQ packet [MQTT-3.1.2-20].

+ +

 

+ +

If the Server returns a +Server Keep Alive on the CONNACK packet, the Client MUST use that value instead +of the value it sent as the Keep Alive [MQTT-3.1.2-21].

+ +

 

+ +

The Client can send PINGREQ at any time, irrespective of the +Keep Alive value, and check for a corresponding PINGRESP to determine that the +network and the Server are available.

+ +

 

+ +

If the Keep Alive value is +non-zero and the Server does not receive an MQTT Control Packet from the Client +within one and a half times the Keep Alive time period, it MUST close the +Network Connection to the Client as if the network had failed [MQTT-3.1.2-22].

+ +

 

+ +

If a Client does not receive a PINGRESP packet within a +reasonable amount of time after it has sent a PINGREQ, it SHOULD close the +Network Connection to the Server.

+ +

 

+ +

A Keep Alive value of 0 has the effect of turning off the Keep +Alive mechanism. If Keep Alive is 0 the Client is not obliged to send MQTT +Control Packets on any particular schedule.

+ +

 

+ +

Non-normative comment

+ +

The Server may have other reasons +to disconnect the Client, for instance because it is shutting down. Setting +Keep Alive does not guarantee that the Client will remain connected.

+ +

 

+ +

Non-normative +comment

+ +

The actual value of the Keep Alive +is application specific; typically, this is a few minutes. The maximum value of +65,535 is 18 hours 12 minutes and 15 seconds.

+ +

 

+ +

3.1.2.11 CONNECT Properties

+ +
3.1.2.11.1 Property Length
+ +

The length of the Properties in the CONNECT packet Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +
3.1.2.11.2 +Session Expiry Interval
+ +

17 (0x11) Byte, Identifier of the Session +Expiry Interval.

+ +

Followed by the Four Byte Integer representing the Session Expiry +Interval in seconds. It is a Protocol Error to include the Session Expiry Interval +more than once.

+ +

 

+ +

If the Session Expiry Interval is absent the value 0 is +used. If it is set to 0, or is absent, the Session ends when the Network Connection +is closed.

+ +

 

+ +

If the Session Expiry Interval is 0xFFFFFFFF (UINT_MAX), the +Session does not expire.

+ +

 

+ +

The Client and Server MUST +store the Session State after the Network Connection is closed if the Session +Expiry Interval is greater than 0 [MQTT-3.1.2-23].

+ +

 

+ +

Non-normative comment

+ +

The clock in the Client or Server +may not be running for part of the time interval, for instance because the +Client or Server are not running. This might cause the deletion of the state to +be delayed.

+ +

 

+ +

Refer to section 4.1 for more information about Sessions. +Refer to section 4.1.1 for details and +limitations of stored state.

+ +

 

+ +

When the Session expires the Client +and Server need not process the deletion of state atomically.

+ +

 

+ +

Non-normative +comment

+ +

Setting Clean Start to 1 and a +Session Expiry Interval of 0, is equivalent to setting CleanSession to 1 in the +MQTT Specification Version 3.1.1. Setting Clean Start to 0 and no Session +Expiry Interval, is equivalent to setting CleanSession to 0 in the MQTT +Specification Version 3.1.1.

+ +

 

+ +

Non-normative +comment

+ +

A Client that only wants to process +messages while connected will set the Clean Start to 1 and set the Session +Expiry Interval to 0. It will not receive Application Messages published before +it connected and has to subscribe afresh to any topics that it is interested in +each time it connects.

+ +

 

+ +

Non-normative +comment

+ +

A Client might be connecting to a Server +using a network that provides intermittent connectivity. This Client can use a +short Session Expiry Interval so that it can reconnect when the network is +available again and continue reliable message delivery. If the Client does not +reconnect, allowing the Session to expire, then Application Messages will be +lost.

+ +

 

+ +

Non-normative comment

+ +

When a Client connects with a long +Session Expiry Interval, it is requesting that the Server maintain its MQTT +session state after it disconnects for an extended period. Clients should only +connect with a long Session Expiry Interval if they intend to reconnect to the +Server at some later point in time. When a Client has determined that it has no +further use for the Session it should disconnect with a Session Expiry Interval +set to 0.

+ +

 

+ +

Non-normative comment

+ +

The Client should always use the Session +Present flag in the CONNACK to determine whether the Server has a Session State +for this Client.

+ +

 

+ +

Non-normative +comment

+ +

The Client can avoid implementing +its own Session expiry and instead rely on the Session Present flag returned +from the Server to determine if the Session had expired. If the Client does +implement its own Session expiry, it needs to store the time at which the Session +State will be deleted as part of its Session State.

+ +

 

+ +
3.1.2.11.3 +Receive Maximum
+ +

33 (0x21) Byte, Identifier of the Receive Maximum.

+ +

Followed by the Two Byte Integer representing the Receive +Maximum value. It is a Protocol Error to include the Receive Maximum value more +than once or for it to have the value 0.

+ +

 

+ +

The Client uses this value to limit the number of QoS 1 and +QoS 2 publications that it is willing to process concurrently. There is no mechanism +to limit the QoS 0 publications that the Server might try to send.

+ +

 

+ +

The value of Receive Maximum applies only to the current +Network Connection. If the Receive Maximum value is +absent then its value defaults to 65,535.

+ +

 

+ +

Refer to section +4.9 Flow Control for details of how the Receive Maximum is used.

+ +

 

+ +
3.1.2.11.4 +Maximum Packet Size
+ +

39 (0x27) Byte, Identifier of the Maximum Packet Size.

+ +

Followed by a Four Byte Integer +representing the Maximum Packet Size the Client is willing to accept. If the +Maximum Packet Size is not present, no limit on the packet size is imposed +beyond the limitations in the protocol as a result of the remaining length +encoding and the protocol header sizes.

+ +

 

+ +

It is a Protocol Error to include the Maximum Packet Size +more than once, or for the value to be set to zero.

+ +

 

+ +

            Non-normative comment

+ +

It is the +responsibility of the application to select a suitable Maximum Packet Size +value if it chooses to restrict the Maximum Packet Size.

+ +

 

+ +

The packet size is the total number of +bytes in an MQTT Control Packet, as defined in section 2.1.4. The Client uses the Maximum Packet Size to inform the Server that +it will not process packets exceeding this limit.

+ +

 

+ +

The Server MUST +NOT send packets exceeding Maximum Packet Size to the Client [MQTT-3.1.2-24]. If a Client +receives a packet whose size exceeds this limit, this is a Protocol Error, the +Client uses DISCONNECT with Reason Code 0x95 (Packet too large), as described +in section 4.13.

+ +

 

+ +

Where a Packet is +too large to send, the Server MUST discard it without sending it and then +behave as if it had completed sending that Application Message [MQTT-3.1.2-25].

+ +

 

+ +

In the case of a Shared Subscription where the +message is too large to send to one or more of the Clients but other Clients can +receive it, the Server can choose either discard the message without sending +the message to any of the Clients, or to send the message to one of the Clients +that can receive it.

+ +

 

+ +

Non-normative +comment

+ +

Where a packet is discarded without +being sent, the Server could place the discarded packet on a ‘dead letter +queue’ or perform other diagnostic action. Such actions are outside the scope +of this specification.

+ +

 

+ +
3.1.2.11.5 +Topic Alias Maximum
+ +

34 (0x22) Byte, Identifier of the Topic Alias Maximum. +

+ +

Followed by the Two Byte Integer representing the Topic +Alias Maximum value. It is a Protocol Error to include the Topic Alias Maximum +value more than once. If the Topic Alias Maximum property is absent, the +default value is 0.

+ +

 

+ +

This value indicates the highest value that the Client will +accept as a Topic Alias sent by the Server. The Client uses this value to limit +the number of Topic Aliases that it is willing to hold on this Connection. The Server MUST NOT send a Topic Alias in a PUBLISH +packet to the Client greater than Topic Alias Maximum [MQTT-3.1.2-26]. A value of 0 indicates that the +Client does not accept any Topic Aliases on this connection. If Topic Alias Maximum is absent or zero, the Server +MUST NOT send any Topic Aliases to the Client [MQTT-3.1.2-27].

+ +

 

+ +
3.1.2.11.6 Request Response Information
+ +

25 (0x19) Byte, Identifier of the Request Response +Information.

+ +

Followed by a Byte with a value of either 0 or 1. It is +Protocol Error to include the Request Response Information more than once, or +to have a value other than 0 or 1. If the Request Response Information is +absent, the value of 0 is used.

+ +

 

+ +

The Client uses this value to request the Server to return +Response Information in the CONNACK. A value of +0 indicates that the Server MUST NOT return Response Information [MQTT-3.1.2-28]. If the value is 1 the Server MAY +return Response Information in the CONNACK packet.

+ +

 

+ +

Non-normative +comment

+ +

The Server can choose not to +include Response Information in the CONNACK, even if the Client requested it.

+ +

 

+ +

Refer to section 4.10 for more information about Request +/ Response.

+ +

 

+ +
3.1.2.11.7 +Request Problem Information
+ +

23 (0x17) Byte, Identifier of the Request Problem +Information.

+ +

Followed by a Byte with a value of either 0 or 1. It is a +Protocol Error to include Request Problem Information more than once, or to +have a value other than 0 or 1. If the Request Problem Information is absent, the +value of 1 is used.

+ +

 

+ +

The Client uses this value to indicate whether the Reason +String or User Properties are sent in the case of failures.

+ +

 

+ +

If the value of Request +Problem Information is 0, the Server MAY return a Reason String or User +Properties on a CONNACK or DISCONNECT packet, but MUST NOT send a Reason String +or User Properties on any packet other than PUBLISH, +CONNACK, or DISCONNECT [MQTT-3.1.2-29]. +If the value is 0 and the Client receives a Reason String or User Properties in +a packet other than PUBLISH, CONNACK, or DISCONNECT, it uses a DISCONNECT packet +with Reason Code 0x82 (Protocol Error) as described in section +4.13 Handling errors.

+ +

 

+ +

If this value is 1, the Server MAY return a Reason String or +User Properties on any packet where it is allowed.

+ +

 

+ +
3.1.2.11.8 User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by a UTF-8 String Pair.

+ +

 

+ +

The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

Non-normative +comment

+ +

User Properties on the CONNECT +packet can be used to send connection related properties from the Client to the +Server. The meaning of these properties is not defined by this specification.

+ +

 

+ +
3.1.2.11.9 Authentication Method
+ +

21 (0x15) Byte, Identifier of the Authentication +Method.

+ +

Followed by a UTF-8 Encoded String containing the name of +the authentication method used for extended authentication .It is a Protocol +Error to include Authentication Method more than once.

+ +

If Authentication Method is absent, extended authentication +is not performed. Refer to section 4.12.

+ +

 

+ +

If a Client sets an Authentication +Method in the CONNECT, the Client MUST NOT send any packets other than AUTH or +DISCONNECT packets until it has received a CONNACK packet [MQTT-3.1.2-30].

+ +

 

+ +
3.1.2.11.10 Authentication Data
+ +

22 (0x16) Byte, Identifier of the Authentication +Data.

+ +

Followed by Binary Data containing authentication data. It +is a Protocol Error to include Authentication Data if there is no +Authentication Method. It is a Protocol Error to include Authentication Data +more than once.

+ +

 

+ +

The contents of this data are defined by the authentication +method. Refer to section 4.12 for more +information about extended authentication.

+ +

 

+ +

3.1.2.12 Variable Header non-normative example

+ +

Figure 3‑6 +- Variable Header example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Protocol Name

+
+

byte 1

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Length LSB (4)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

byte 3

+
+

‘M’

+
+

0

+
+

1

+
+

0

+
+

0

+
+

1

+
+

1

+
+

0

+
+

1

+
+

byte 4

+
+

‘Q’

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 5

+
+

‘T’

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

byte 6

+
+

‘T’

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

Protocol Version

+
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 7

+
+

Version (5)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

Connect Flags

+
+

 

+

 

+

 

+

 

+

byte 8

+
+

User Name Flag (1)

+

Password Flag (1)

+

Will Retain (0)

+

Will QoS (01)

+

Will Flag (1)

+

Clean Start(1)

+

Reserved (0)

+
+

 

+

 

+

 

+

 

+

1

+
+

 

+

 

+

 

+

 

+

1

+
+

 

+

 

+

 

+

 

+

0

+
+

 

+

 

+

 

+

 

+

0

+
+

 

+

 

+

 

+

 

+

1

+
+

 

+

 

+

 

+

 

+

1

+
+

 

+

 

+

 

+

 

+

1

+
+

 

+

 

+

 

+

 

+

0

+
+

Keep Alive

+
+

byte 9

+
+

Keep Alive MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 10

+
+

Keep Alive LSB (10)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

Properties

+
+

byte 11

+
+

Length (5)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

byte 12

+
+

Session Expiry Interval identifier (17)

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 13

+
+

Session Expiry Interval (10)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 14

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 15

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 16

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+ +

 

+ +

3.1.3 CONNECT Payload

+ +

The Payload of the CONNECT +packet contains one or more length-prefixed fields, whose presence is +determined by the flags in the Variable Header. These fields, if present, MUST +appear in the order Client Identifier, Will Properties, Will Topic, Will Payload, +User Name, Password [MQTT-3.1.3-1].

+ +

 

+ +

3.1.3.1 Client Identifier +(ClientID)

+ +

The Client Identifier (ClientID) +identifies the Client to the Server. Each Client connecting to the Server has a +unique ClientID. The ClientID MUST be used by +Clients and by Servers to identify state that they hold relating to this MQTT +Session between the Client and the Server [MQTT-3.1.3-2]. Refer to section 4.1 for more information about Session State.

+ +

 

+ +

The +ClientID MUST be present and is the first field in the CONNECT packet Payload +[MQTT-3.1.3-3].

+ +

 

+ +

The ClientID MUST be a UTF-8 +Encoded String as defined in section +1.5.4 [MQTT-3.1.3-4].

+ +

 

+ +

The Server MUST allow ClientID’s +which are between 1 and 23 UTF-8 encoded bytes in length, and that contain only +the characters

+ +

"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +[MQTT-3.1.3-5].

+ +

 

+ +

The Server MAY allow ClientID’s that contain more than 23 encoded +bytes. The Server MAY allow ClientID’s that contain characters not included in +the list given above.

+ +

 

+ +

A Server MAY allow a Client +to supply a ClientID that has a length of zero bytes, however if it does so the +Server MUST treat this as a special case and assign a unique ClientID to that +Client [MQTT-3.1.3-6]. It MUST then process the CONNECT packet as if the +Client had provided that unique ClientID, and MUST +return the Assigned Client Identifier in the CONNACK packet [MQTT-3.1.3-7].

+ +

 

+ +

If the Server rejects the +ClientID it MAY respond to the CONNECT packet with a CONNACK using Reason Code +0x85 (Client Identifier not valid) as described in section 4.13 Handling errors, and then it MUST close the Network +Connection [MQTT-3.1.3-8].

+ +

 

+ +

Non-normative +comment

+ +

A Client implementation could +provide a convenience method to generate a random ClientID. Clients using this +method should take care to avoid creating long-lived orphaned Sessions.

+ +

 

+ +

3.1.3.2 Will Properties

+ +

If the Will Flag is set to 1, the Will Properties is the +next field in the Payload. The Will Properties field defines the Application +Message properties to be sent with the Will Message when it is published, and +properties which define when to publish the Will Message. The Will Properties +consists of a Property Length and the Properties.

+ +

 

+ +
3.1.3.2.1 Property Length
+ +

The length of the Properties in the Will Properties encoded +as a Variable Byte Integer.

+ +

 

+ +
3.1.3.2.2 Will +Delay Interval
+ +

24 (0x18) Byte, Identifier of the Will Delay +Interval.

+ +

Followed by the Four Byte Integer representing the Will +Delay Interval in seconds. It is a Protocol Error to include the Will Delay Interval +more than once. If the Will Delay Interval is absent, the default value is 0 +and there is no delay before the Will Message is published.

+ +

 

+ +

The Server delays publishing the Client’s Will Message until +the Will Delay Interval has passed or the Session ends, whichever happens +first. If a new Network Connection to this +Session is made before the Will Delay Interval has passed, the Server MUST NOT +send the Will Message [MQTT-3.1.3-9].

+ +

 

+ +

Non-normative comment

+ +

One use of this is to avoid +publishing Will Messages if there is a temporary network disconnection and the +Client succeeds in reconnecting and continuing its Session before the Will +Message is published.

+ +

 

+ +

Non-normative comment

+ +

If a Network Connection uses a +Client Identifier of an existing Network Connection to the Server, the Will +Message for the exiting connection is sent unless the new connection specifies +Clean Start of 0 and the Will Delay is greater than zero. If the Will Delay is 0 +the Will Message is sent at the close of the existing Network Connection, and +if Clean Start is 1 the Will Message is sent because the Session ends.

+ +

 

+ +
3.1.3.2.3 Payload Format +Indicator
+ +

1 (0x01) Byte, Identifier of the Payload Format +Indicator.

+ +

Followed by the value of the Payload Format Indicator, +either of:

+ +

·         +0 (0x00) Byte Indicates that the Will Message is unspecified +bytes, which is equivalent to not sending a Payload Format Indicator.

+ +

·         +1 (0x01) Byte Indicates that the Will Message is UTF-8 Encoded +Character Data. The UTF-8 data in the Payload MUST be well-formed UTF-8 as defined by the +Unicode specification [Unicode] and restated in RFC 3629 [RFC3629].

+ +

 

+ +

It is a Protocol Error to include the Payload Format Indicator +more than once. The Server MAY validate that the Will Message is of the format +indicated, and if it is not send a CONNACK with the Reason Code of 0x99 (Payload +format invalid) as described in section 4.13.

+ +

 

+ +
3.1.3.2.4 Message Expiry Interval
+ +

2 (0x02) Byte, Identifier of the Message Expiry Interval. +

+ +

Followed by the Four Byte Integer representing the Message +Expiry Interval. It is a Protocol Error to include the Message Expiry Interval +more than once.

+ +

 

+ +

If present, the Four Byte value is the lifetime of the Will +Message in seconds and is sent as the Publication Expiry Interval when the +Server publishes the Will Message.

+ +

 

+ +

If absent, no Message Expiry Interval is sent when the +Server publishes the Will Message.

+ +

 

+ +
3.1.3.2.5 Content Type
+ +

3 (0x03) Identifier of +the Content Type.

+ +

Followed by a UTF-8 Encoded String +describing the content of the Will Message. It is a Protocol Error to include the Content Type more than +once. The value of the Content Type is defined by the sending and receiving +application.

+ +

 

+ +
3.1.3.2.6 Response Topic
+ +

8 (0x08) +Byte, Identifier of the +Response Topic.

+ +

Followed by a +UTF-8 Encoded String which is used as the Topic Name for a response message. It +is a Protocol Error to include the Response Topic more than once. The presence +of a Response Topic identifies the Will Message as a Request.

+ +

 

+ +

Refer to section 4.10 for more information about Request / Response.

+ +

 

+ +
3.1.3.2.7 Correlation Data
+ +

9 (0x09) Byte, Identifier of the Correlation Data.

+ +

Followed by Binary Data. The Correlation Data is used by the +sender of the Request Message to identify which request the Response Message is +for when it is received. It is a Protocol Error to include Correlation Data +more than once. If the Correlation Data is not present, the Requester does not +require any correlation data.

+ +

 

+ +

The value of the Correlation Data only has meaning to the +sender of the Request Message and receiver of the Response Message.

+ +

 

+ +

Refer to section 4.10 for +more information about Request / Response

+ +

 

+ +
3.1.3.2.8 User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by a UTF-8 String Pair. The User Property is +allowed to appear multiple times to represent multiple name, value pairs. The +same name is allowed to appear more than once.

+ +

 

+ +

The Server MUST maintain the +order of User Properties when publishing the Will Message [MQTT-3.1.3-10].

+ +

 

+ +

Non-normative comment

+ +

This property is intended to +provide a means of transferring application layer name-value tags whose meaning +and interpretation are known only by the application programs responsible for +sending and receiving them.

+ +

 

+ +

3.1.3.3 Will Topic

+ +

If the Will Flag is set to 1, the Will Topic is the next +field in the Payload. The Will Topic MUST be a +UTF-8 Encoded String as defined in section +1.5.4 [MQTT-3.1.3-11].

+ +

 

+ +

3.1.3.4 Will Payload

+ +

If the Will Flag is set to 1 the Will Payload is the next +field in the Payload. The Will Payload defines the Application Message Payload +that is to be published to the Will Topic as described in section 3.1.2.5. This field consists of Binary Data.

+ +

 

+ +

3.1.3.5 User Name

+ +

If the User Name Flag is set +to 1, the User Name is the next field in the Payload. The User Name MUST be a +UTF-8 Encoded String as defined in section +1.5.4 [MQTT-3.1.3-12]. It can be used by the Server for authentication and +authorization.

+ +

 

+ +

3.1.3.6 Password

+ +

If the Password Flag is set to 1, the Password is the next +field in the Payload. The Password field is Binary Data. Although this field is +called Password, it can be used to carry any credential information.

+ +

 

+ +

3.1.4 CONNECT Actions

+ +

Note that a Server MAY support multiple protocols (including +other versions of the MQTT protocol) on the same TCP port or other network +endpoint. If the Server determines that the protocol is MQTT v5.0 then it +validates the connection attempt as follows.

+ +

 

+ +

1.     If the +Server does not receive a CONNECT packet within a reasonable amount of time +after the Network Connection is established, the Server SHOULD close the Network +Connection.

+ +

2.     The Server MUST validate that the CONNECT packet matches +the format described in section 3.1 +and close the Network Connection if it does not match [MQTT-3.1.4-1]. The +Server MAY send a CONNACK with a Reason Code of 0x80 or greater as described in +section 4.13 before closing the Network Connection.

+ +
    +
  1. The + Server MAY check that the contents of the CONNECT packet meet any further + restrictions and SHOULD perform authentication and authorization checks. If + any of these checks fail, it MUST close the Network Connection [MQTT-3.1.4-2]. Before closing the Network + Connection, it MAY send an appropriate CONNACK response with a Reason Code + of 0x80 or greater as described in section + 3.2 and section 4.13.
  2. +
+ +

 

+ +

If validation is successful, the +Server performs the following steps.

+ +

 

+ +

1.     If the ClientID represents a Client already connected +to the Server, the Server sends a DISCONNECT packet to the existing Client with +Reason Code of 0x8E (Session taken over) as described in section 4.13 and MUST close the Network Connection of the +existing Client [MQTT-3.1.4-3]. If the +existing Client has a Will Message, that Will Message is published as described +in section 3.1.2.5.

+ +

 

+ +

Non-normative comment

+ +

If the Will Delay Interval of the +existing Network Connection is 0 and there is a Will Message, it will be sent +because the Network Connection is closed. If the Session Expiry Interval of the +existing Network Connection is 0, or the new Network Connection has Clean Start +set to 1 then if the existing Network Connection has a Will Message it will be +sent because the original Session is ended on the takeover.

+ +

 

+ +

2.     The Server MUST perform the processing of Clean Start +that is described in section 3.1.2.4 [MQTT-3.1.4-4].

+ +

 

+ +

3.     The Server MUST acknowledge the CONNECT packet with a +CONNACK packet containing a 0x00 (Success) Reason Code [MQTT-3.1.4-5].

+ +

 

+ +

Non-normative comment

+ +

It is recommended that +authentication and authorization checks be performed if the Server is being +used to process any form of business critical data. If these checks succeed, +the Server responds by sending CONNACK with a 0x00 (Success) Reason Code. If +they fail, it is suggested that the Server does not send a CONNACK at all, as +this could alert a potential attacker to the presence of the MQTT Server and +encourage such an attacker to launch a denial of service or password-guessing +attack.

+ +

 

+ +

4.     Start +message delivery and Keep Alive monitoring.

+ +

 

+ +

Clients are allowed to send further MQTT Control Packets +immediately after sending a CONNECT packet; Clients need not wait for a CONNACK +packet to arrive from the Server. If the Server +rejects the CONNECT, it MUST NOT process any data sent by the Client after the +CONNECT packet except AUTH packets [MQTT-3.1.4-6].

+ +

 

+ +

Non-normative comment

+ +

Clients typically wait for a +CONNACK packet, However, if the Client exploits its freedom to send MQTT Control +Packets before it receives a CONNACK, it might simplify the Client +implementation as it does not have to police the connected state. The Client accepts +that any data that it sends before it receives a CONNACK packet from the Server +will not be processed if the Server rejects the connection.

+ +

 

+ +

Non-normative comment

+ +

Clients that send MQTT Control +Packets before they receive CONNACK will be unaware of the Server constraints +and whether any existing Session is being used.

+ +

 

+ +

Non-normative comment

+ +

The Server can limit reading from +the Network Connection or close the Network Connection if the Client sends too +much data before authentication is complete. This is suggested as a way of +avoiding denial of service attacks.

+ +

 

+ +

3.2 CONNACK – Connect +acknowledgement

+ +

The CONNACK packet is the packet sent by the Server in +response to a CONNECT packet received from a Client. The Server MUST send a CONNACK with a 0x00 (Success) Reason Code before +sending any Packet other than AUTH [MQTT-3.2.0-1]. +The Server MUST NOT send more than one CONNACK +in a Network Connection [MQTT-3.2.0-2].

+ +

 

+ +

If the Client does not receive a +CONNACK packet from the Server within a reasonable amount of time, the Client +SHOULD close the Network Connection. A "reasonable" amount of time +depends on the type of application and the communications infrastructure.

+ +

 

+ +

3.2.1 CONNACK Fixed Header

+ +

The Fixed Header format is illustrated in Figure 3-7.

+ +

Figure 3‑7 – CONNACK packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + Type (2)

+
+

Reserved

+
+

 

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +

3.2.2 CONNACK Variable Header

+ +

The Variable Header of the CONNACK Packet contains the +following fields in the order: Connect Acknowledge Flags, Connect Reason Code, and +Properties. The rules for encoding Properties are described in section 2.2.2.

+ +

 

+ +

3.2.2.1 Connect Acknowledge Flags

+ +

Byte 1 is the "Connect +Acknowledge Flags". Bits 7-1 are reserved and MUST be set to 0 [MQTT-3.2.2-1].

+ +

 

+ +

Bit 0 is the Session Present Flag.

+ +

 

+ +
3.2.2.1.1 Session Present
+ +

Position: bit 0 of the Connect Acknowledge Flags.

+ +

 

+ +

The Session Present flag informs the Client whether the +Server is using Session State from a previous connection for this ClientID. +This allows the Client and Server to have a consistent view of the Session +State.

+ +

 

+ +

If the Server accepts a +connection with Clean Start set to 1, the Server MUST set Session Present to 0 +in the CONNACK packet in addition to setting a 0x00 (Success) Reason Code in +the CONNACK packet [MQTT-3.2.2-2].

+ +

 

+ +

If the Server accepts a +connection with Clean Start set to 0 and the Server has Session State for the +ClientID, it MUST set Session Present to 1 in the CONNACK packet, otherwise it +MUST set Session Present to 0 in the CONNACK packet. In both cases it MUST set +a 0x00 (Success) Reason Code in the CONNACK packet [MQTT-3.2.2-3].

+ +

 

+ +

If the value of Session Present received by the Client from +the Server is not as expected, the Client proceeds as follows:

+ +

·         +If the Client does not have +Session State and receives Session Present set to 1 it MUST close the Network +Connection [MQTT-3.2.2-4]. If it wishes +to restart with a new Session the Client can reconnect using Clean Start set to +1.

+ +

·         +If the Client does have Session +State and receives Session Present set to 0 it MUST discard its Session State +if it continues with the Network Connection [MQTT-3.2.2-5].

+ +

 

+ +

 

+ +

If a Server sends a CONNACK +packet containing a non-zero Reason Code it MUST set Session Present to 0 +[MQTT-3.2.2-6].

+ +

 

+ +

3.2.2.2 Connect Reason Code

+ +

Byte 2 in the Variable Header is the Connect Reason Code.

+ +

 

+ +

The values the Connect Reason Code are shown below. If a +well formed CONNECT packet is received by the Server, but the Server is unable +to complete the Connection the Server MAY send a CONNACK packet containing the +appropriate Connect Reason code from this table. If +a Server sends a CONNACK packet containing a Reason code of 128 or greater it +MUST then close the Network Connection [MQTT-3.2.2-7].

+ +

+ +

Table +3‑1 - Connect Reason Code values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

The Connection is accepted.

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

The Server does not wish to reveal the reason for the + failure, or none of the other Reason Codes apply.

+
+

129

+
+

0x81

+
+

Malformed Packet

+
+

Data within the CONNECT packet could not be correctly parsed. +

+
+

130

+
+

0x82

+
+

Protocol Error

+
+

Data in the CONNECT packet does not conform to this + specification.

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

The CONNECT is valid but is not accepted by this Server.

+
+

132

+
+

0x84

+
+

Unsupported Protocol Version

+
+

The Server does not support the version of the MQTT + protocol requested by the Client.

+
+

133

+
+

0x85

+
+

Client Identifier not valid

+
+

The Client Identifier is a valid string but is not allowed + by the Server.

+
+

134

+
+

0x86

+
+

Bad User Name or Password

+
+

The Server does not accept the User Name or Password + specified by the Client

+
+

135

+
+

0x87

+
+

Not authorized

+
+

The Client is not authorized to connect.

+
+

136

+
+

0x88

+
+

Server unavailable

+
+

The MQTT Server is not available.

+
+

137

+
+

0x89

+
+

Server busy

+
+

The Server is busy. Try again later.

+
+

138

+
+

0x8A

+
+

Banned

+
+

This Client has been banned by administrative action. + Contact the server administrator.

+
+

140

+
+

0x8C

+
+

Bad authentication method

+
+

The authentication method is not supported or does not + match the authentication method currently in use.

+
+

144

+
+

0x90

+
+

Topic Name invalid

+
+

The Will Topic Name is not malformed, but is not accepted + by this Server.

+
+

149

+
+

0x95

+
+

Packet too large

+
+

The CONNECT packet exceeded the maximum permissible size.

+
+

151

+
+

0x97

+
+

Quota exceeded

+
+

An implementation or administrative imposed limit has been + exceeded.

+
+

153

+
+

0x99

+
+

Payload format invalid

+
+

The Will Payload does not match the specified Payload + Format Indicator.

+
+

154

+
+

0x9A

+
+

Retain not supported

+
+

The Server does not support retained messages, and Will + Retain was set to 1.

+
+

155

+
+

0x9B

+
+

QoS not supported

+
+

The Server does not support the QoS set in Will QoS.

+
+

156

+
+

0x9C

+
+

Use another server

+
+

The Client should temporarily use another server.

+
+

157

+
+

0x9D

+
+

Server moved

+
+

The Client should permanently use another server.

+
+

159

+
+

0x9F

+
+

Connection rate exceeded

+
+

The connection rate limit has been exceeded.

+
+ +

 

+ +

The Server sending the +CONNACK packet MUST use one of the Connect Reason Code valuesT-3.2.2-8].

+ +

 

+ +

Non-normative +comment

+ +

Reason Code 0x80 (Unspecified +error) may be used where the Server knows the reason for the failure but does +not wish to reveal it to the Client, or when none of the other Reason Code +values applies.

+ +

 

+ +

The Server may choose to close the Network +Connection without sending a CONNACK to enhance security in the case where an +error is found on the CONNECT. For instance, when on a public network and the +connection has not been authorized it might be unwise to indicate that this is +an MQTT Server.

+ +

 

+ +

3.2.2.3 CONNACK Properties

+ +
3.2.2.3.1 Property Length
+ +

This is the length of the Properties in the CONNACK packet Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +
3.2.2.3.2 Session +Expiry Interval
+ +

17 (0x11) Byte, Identifier of the Session Expiry +Interval.

+ +

Followed by the Four Byte Integer representing the Session +Expiry Interval in seconds. It is a Protocol Error to include the Session +Expiry Interval more than once.

+ +

 

+ +

If the Session Expiry Interval is absent the value in the +CONNECT Packet used. The server uses this property to inform the Client that it +is using a value other than that sent by the Client in the CONNACK. Refer to section +3.1.2.11.2 for a description of the use of Session Expiry Interval.

+ +

 

+ +
3.2.2.3.3 Receive Maximum
+ +

33 (0x21) Byte, Identifier of the Receive Maximum.

+ +

Followed by the Two Byte Integer representing the Receive +Maximum value. It is a Protocol Error to include the Receive Maximum value more +than once or for it to have the value 0.

+ +

 

+ +

The Server uses this value to limit the number of QoS 1 and +QoS 2 publications that it is willing to process concurrently for the Client. It +does not provide a mechanism to limit the QoS 0 publications that the Client +might try to send.

+ +

 

+ +

If the Receive Maximum value is +absent, then its value defaults to 65,535.

+ +

 

+ +

Refer to section +4.9 Flow Control for details of how the Receive Maximum is used.

+ +

 

+ +
3.2.2.3.4 Maximum QoS
+ +

36 (0x24) Byte, Identifier of the Maximum QoS.

+ +

Followed by a Byte with a value of either 0 or 1. It is a +Protocol Error to include Maximum QoS more than once, or to have a value other +than 0 or 1. If the Maximum QoS is absent, the Client uses a Maximum QoS of 2.

+ +

 

+ +

If a Server does not support +QoS 1 or QoS 2 PUBLISH packets it MUST send a Maximum QoS in the CONNACK packet +specifying the highest QoS it supports [MQTT-3.2.2-9]. +A Server that does not support QoS 1 or QoS 2 +PUBLISH packets MUST still accept SUBSCRIBE packets containing a Requested QoS +of 0, 1 or 2 [MQTT-3.2.2-10].

+ +

 

+ +

If a Client receives a +Maximum QoS from a Server, it MUST NOT send PUBLISH packets at a QoS level exceeding +the Maximum QoS level specified [MQTT-3.2.2-11]. +It is a Protocol Error if the Server receives a PUBLISH packet with a QoS +greater than the Maximum QoS it specified. In this case use DISCONNECT with +Reason Code 0x9B (QoS not supported) as described in section +4.13 Handling errors.

+ +

 

+ +

If a Server receives a +CONNECT packet containing a Will QoS that exceeds its capabilities, it MUST +reject the connection. It SHOULD use a CONNACK packet with Reason Code 0x9B +(QoS not supported) as described in section 4.13 Handling errors, and MUST close the Network Connection +[MQTT-3.2.2-12].

+ +

 

+ +

Non-normative +comment

+ +

A Client does not need to support +QoS 1 or QoS 2 PUBLISH packets. If this is the case, the Client simply +restricts the maximum QoS field in any SUBSCRIBE commands it sends to a value +it can support.

+ +

 

+ +
3.2.2.3.5 +Retain Available
+ +

37 (0x25) Byte, Identifier of Retain Available.

+ +

Followed by a Byte field. If present, this byte declares +whether the Server supports retained messages. A value of 0 means that retained +messages are not supported. A value of 1 means retained messages are supported. +If not present, then retained messages are supported. It is a Protocol Error to +include Retain Available more than once or to use a value other than 0 or 1.

+ +

 

+ +

If a Server receives a +CONNECT packet containing a Will Message with the Will Retain set to 1, and it +does not support retained messages, the Server MUST reject the connection +request. It SHOULD send CONNACK with Reason Code 0x9A (Retain not supported) +and then it MUST close the Network Connection [MQTT-3.2.2-13]. +

+ +

 

+ +

A Client receiving Retain +Available set to 0 from the Server MUST NOT send a PUBLISH packet with the +RETAIN flag set to 1 [MQTT-3.2.2-14]. If +the Server receives such a packet, this is a Protocol Error. The Server SHOULD +send a DISCONNECT with Reason Code of 0x9A (Retain not supported) as described +in section 4.13.

+ +

 

+ +
3.2.2.3.6 Maximum Packet Size
+ +

39 (0x27) Byte, Identifier of the Maximum Packet +Size.

+ +

Followed by a Four Byte Integer representing the Maximum +Packet Size the Server is willing to accept. If the Maximum Packet Size is not +present, there is no limit on the packet size imposed beyond the limitations in +the protocol as a result of the remaining length encoding and the protocol +header sizes.

+ +

 

+ +

It is a Protocol Error to include the Maximum Packet Size more +than once, or for the value to be set to zero.

+ +

 

+ +

The packet size is the total number +of bytes in an MQTT Control Packet, as defined in section 2.1.4. The Server uses the +Maximum Packet Size to inform the Client that it will not process packets whose +size exceeds this limit.

+ +

 

+ +

The Client MUST +NOT send packets exceeding Maximum Packet Size to the Server [MQTT-3.2.2-15]. If a Server receives a packet whose size exceeds this limit, this is +a Protocol Error, the Server uses DISCONNECT with Reason Code 0x95 (Packet too large), +as described in section 4.13.

+ +

 

+ +
3.2.2.3.7 Assigned Client Identifier
+ +

18 (0x12) Byte, Identifier of the Assigned Client +Identifier.

+ +

Followed by the UTF-8 string which is the Assigned Client +Identifier. It is a Protocol Error to include the Assigned Client Identifier +more than once.

+ +

 

+ +

The Client Identifier which was assigned by the +Server because a zero length Client Identifier was found in the CONNECT packet.

+ +

 

+ +

If the Client connects using +a zero length Client Identifier, the Server MUST respond with a CONNACK +containing an Assigned Client Identifier. The Assigned Client Identifier MUST +be a new Client Identifier not used by any other Session currently in the +Server [MQTT-3.2.2-16].

+ +

 

+ +
3.2.2.3.8 +Topic Alias Maximum
+ +

34 (0x22) Byte, Identifier of the Topic Alias Maximum. +

+ +

Followed by the Two Byte Integer representing the Topic +Alias Maximum value. It is a Protocol Error to include the Topic Alias Maximum +value more than once. If the Topic Alias Maximum property is absent, the +default value is 0.

+ +

 

+ +

This value indicates the highest value that the Server will +accept as a Topic Alias sent by the Client. The Server uses this value to limit +the number of Topic Aliases that it is willing to hold on this Connection. The Client MUST NOT send a Topic Alias in a PUBLISH +packet to the Server greater than this value [MQTT-3.2.2-17]. +A value of 0 indicates that the Server does not accept any Topic Aliases on +this connection. If Topic Alias Maximum is +absent or 0, the Client MUST NOT send any Topic Aliases on to the Server +[MQTT-3.2.2-18].

+ +

 

+ +
3.2.2.3.9 +Reason String
+ +

31 (0x1F) Byte Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is a human readable string +designed for diagnostics and SHOULD NOT be parsed by the Client.

+ +

 

+ +

The Server uses this value to give additional information to +the Client. The Server MUST NOT send this +property if it would increase the size of the CONNACK packet beyond the Maximum +Packet Size specified by the Client [MQTT-3.2.2-19]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +

Non-normative +comment

+ +

Proper uses for the reason string +in the Client would include using this information in an exception thrown by the +Client code, or writing this string to a log.

+ +

 

+ +
3.2.2.3.10 +User Property
+ +

38 (0x26) Byte, Identifier +of User Property.

+ +

Followed by a UTF-8 +String Pair. This property can be used to provide additional information to the +Client including diagnostic information. The Server +MUST NOT send this property if it would increase the size of the CONNACK packet +beyond the Maximum Packet Size specified by the Client [MQTT-3.2.2-20]. The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

The content and meaning of this +property is not defined by this specification. The receiver of a CONNACK +containing this property MAY ignore it.

+ +

 

+ +
3.2.2.3.11 +Wildcard Subscription Available
+ +

40 (0x28) Byte, Identifier of Wildcard Subscription +Available.

+ +

Followed by a Byte field. If present, this byte declares +whether the Server supports Wildcard Subscriptions. A value is 0 means that +Wildcard Subscriptions are not supported. A value of 1 means Wildcard +Subscriptions are supported. If not present, then Wildcard Subscriptions are +supported. It is a Protocol Error to include the Wildcard Subscription +Available more than once or to send a value other than 0 or 1.

+ +

 

+ +

If the Server receives a SUBSCRIBE packet containing a Wildcard +Subscription and it does not support Wildcard Subscriptions, this is a Protocol +Error. The Server uses DISCONNECT with Reason Code 0xA2 (Wildcard Subscriptions +not supported) as described in section 4.13.

+ +

 

+ +

If a Server supports Wildcard Subscriptions, it can still reject +a particular subscribe request containing a Wildcard Subscription. In this case +the Server MAY send a SUBACK Control Packet with a Reason Code 0xA2 (Wildcard +Subscriptions not supported).

+ +

 

+ +
3.2.2.3.12 +Subscription Identifiers Available
+ +

41 (0x29) Byte, Identifier of Subscription Identifier +Available.

+ +

Followed by a Byte field. If present, this byte declares +whether the Server supports Subscription Identifiers. A value is 0 means that +Subscription Identifiers are not supported. A value of 1 means Subscription +Identifiers are supported. If not present, then Subscription Identifiers are +supported. It is a Protocol Error to include the Subscription Identifier +Available more than once, or to send a value other than 0 or 1.

+ +

 

+ +

If the Server receives a SUBSCRIBE packet containing +Subscription Identifier and it does not support Subscription Identifiers, this +is a Protocol Error. The Server uses DISCONNECT with Reason Code of 0xA1 +(Subscription Identifiers not supported) as described in section +4.13.

+ +

 

+ +
3.2.2.3.13 +Shared Subscription Available
+ +

42 (0x2A) Byte, Identifier of Shared Subscription +Available.

+ +

Followed by a Byte field. If present, this byte declares +whether the Server supports Shared Subscriptions. A value is 0 means that +Shared Subscriptions are not supported. A value of 1 means Shared Subscriptions +are supported. If not present, then Shared Subscriptions are supported. It is a +Protocol Error to include the Shared Subscription Available more than once or +to send a value other than 0 or 1.

+ +

 

+ +

If the Server receives a SUBSCRIBE packet containing Shared +Subscriptions and it does not support Shared Subscriptions, this is a Protocol +Error. The Server uses DISCONNECT with Reason Code 0x9E (Shared Subscriptions +not supported) as described in section 4.13.

+ +

 

+ +
3.2.2.3.14 +Server Keep Alive
+ +

19 (0x13) Byte, Identifier of the Server Keep Alive.

+ +

Followed by a Two Byte Integer with the Keep Alive time +assigned by the Server. If the Server sends a +Server Keep Alive on the CONNACK packet, the Client MUST use this value instead +of the Keep Alive value the Client sent on CONNECT [MQTT-3.2.2-21]. If +the Server does not send the Server Keep Alive, the Server MUST use the Keep +Alive value set by the Client on CONNECT [MQTT-3.2.2-22]. +It is a Protocol Error to include the Server Keep Alive more than once.

+ +

 

+ +

Non-normative +comment

+ +

The primary use of the Server Keep +Alive is for the Server to inform the Client that it will disconnect the Client +for inactivity sooner than the Keep Alive specified by the Client.

+ +

 

+ +
3.2.2.3.15 Response +Information
+ +

26 (0x1A) Byte, Identifier of the Response +Information.

+ +

Followed by a UTF-8 Encoded String which is used as the +basis for creating a Response Topic. The way in which the Client creates a +Response Topic from the Response Information is not defined by this +specification. It is a Protocol Error to include the Response Information more +than once.

+ +

 

+ +

If the Client sends a Request Response Information with a +value 1, it is OPTIONAL for the Server to send the Response Information in the +CONNACK.

+ +

 

+ +

Non-normative +comment

+ +

A common use of this is to pass a +globally unique portion of the topic tree which is reserved for this Client for +at least the lifetime of its Session. This often cannot just be a random name +as both the requesting Client and the responding Client need to be authorized +to use it. It is normal to use this as the root of a topic tree for a +particular Client. For the Server to return this information, it normally needs +to be correctly configured. Using this mechanism allows this configuration to +be done once in the Server rather than in each Client.

+ +

 

+ +

Refer to section 4.10 for more information about Request +/ Response.

+ +

 

+ +
3.2.2.3.16 +Server Reference
+ +

28 (0x1C) Byte, Identifier of the Server Reference.

+ +

Followed by a UTF-8 Encoded String which can be used by the +Client to identify another Server to use. It is a Protocol Error to include the +Server Reference more than once.

+ +

 

+ +

The Server uses a Server Reference in either a CONNACK or +DISCONNECT packet with Reason code of 0x9C (Use another server) or Reason Code +0x9D (Server moved) as described in section 4.13.

+ +

 

+ +

Refer to section 4.11 Server redirection for information +about how Server Reference is used.

+ +

 

+ +
3.2.2.3.17 Authentication Method
+ +

21 (0x15) Byte, Identifier of the Authentication +Method.

+ +

Followed by a UTF-8 Encoded String containing the name of +the authentication method. It is a Protocol Error to include the Authentication +Method more than once. Refer to section +4.12 for more information about extended authentication.

+ +

 

+ +
3.2.2.3.18 Authentication Data
+ +

22 (0x16) Byte, Identifier of the Authentication +Data.

+ +

Followed by Binary Data containing authentication data. The +contents of this data are defined by the authentication method and the state of +already exchanged authentication data. It is a Protocol Error to include the +Authentication Data more than once. Refer to section +4.12 for more information about extended authentication.

+ +

 

+ +

3.2.3 +CONNACK Payload

+ +

The CONNACK packet has no Payload.

+ +

 

+ +

3.3 PUBLISH – Publish message

+ +

A PUBLISH packet is sent from a Client to a Server or from a +Server to a Client to transport an Application Message.

+ +

 

+ +

3.3.1 +PUBLISH Fixed Header

+ +

Figure +3‑8 – PUBLISH packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (3)

+
+

DUP flag

+
+

QoS level

+
+

RETAIN

+
+

 

+
+

0

+
+

0

+
+

1

+
+

1

+
+

X

+
+

X

+
+

X

+
+

X

+
+

byte 2…

+
+

Remaining Length

+
+ +

 

+ +

3.3.1.1 DUP

+ +

Position: byte 1, bit 3.

+ +

If the DUP flag is set to 0, it indicates that this is the +first occasion that the Client or Server has attempted to send this PUBLISH packet. +If the DUP flag is set to 1, it indicates that this might be re-delivery of an +earlier attempt to send the packet.

+ +

 

+ +

The DUP flag MUST be set to +1 by the Client or Server when it attempts to re-deliver a PUBLISH packet +[MQTT-3.3.1-1]. The +DUP flag MUST be set to 0 for all QoS 0 messages [MQTT-3.3.1-2].

+ +

 

+ +

The value of the DUP flag from an incoming PUBLISH packet is +not propagated when the PUBLISH packet is sent to subscribers by the Server. The DUP flag in the outgoing PUBLISH packet is set +independently to the incoming PUBLISH packet, its value MUST be determined +solely by whether the outgoing PUBLISH packet is a retransmission [MQTT-3.3.1-3].

+ +

 

+ +

Non-normative +comment

+ +

The receiver of an MQTT Control +Packet that contains the DUP flag set to 1 cannot assume that it has seen an +earlier copy of this packet.

+ +

 

+ +

Non-normative +comment

+ +

It is important to note that the +DUP flag refers to the MQTT Control Packet itself and not to the Application +Message that it contains. When using QoS 1, it is possible for a Client to +receive a PUBLISH packet with DUP flag set to 0 that contains a repetition of +an Application Message that it received earlier, but with a different Packet +Identifier. Section 2.2.1 provides more +information about Packet Identifiers.

+ +

 

+ +

3.3.1.2 QoS

+ +

Position: byte 1, bits 2-1.

+ +

This field indicates the level of assurance for delivery of +an Application Message. The QoS levels are shown below.

+ +

 

+ +

Table +3‑2 - QoS definitions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

QoS value

+
+

Bit 2

+
+

bit 1

+
+

Description

+
+

0

+
+

0

+
+

0

+
+

At most once delivery

+
+

1

+
+

0

+
+

1

+
+

At least once delivery

+
+

2

+
+

1

+
+

0

+
+

Exactly once delivery

+
+

-

+
+

1

+
+

1

+
+

Reserved – must not be used

+
+ +

 

+ +

If the Server included a Maximum QoS in its CONNACK response +to a Client and it receives a PUBLISH packet with a QoS greater than this, then +it uses DISCONNECT with Reason Code 0x9B (QoS not supported) as described in section 4.13 Handling errors.

+ +

 

+ +

A PUBLISH Packet MUST NOT +have both QoS bits set to 1 [MQTT-3.3.1-4]. +If a Server or Client receives a PUBLISH packet which has both QoS bits set to +1 it is a Malformed Packet. Use DISCONNECT with Reason Code 0x81 (Malformed +Packet) as described in section 4.13.

+ +

 

+ +

3.3.1.3 +RETAIN

+ +

Position: byte 1, bit 0.

+ +

 

+ +

If the RETAIN flag is set to +1 in a PUBLISH packet sent by a Client to a Server, the Server MUST replace any +existing retained message for this topic and store the Application Message +[MQTT-3.3.1-5], so that it can be delivered to +future subscribers whose subscriptions match its Topic Name. If the Payload contains zero bytes it is processed +normally by the Server but any retained message with the same topic name MUST +be removed and any future subscribers for the topic will not receive a retained +message [MQTT-3.3.1-6]. A retained message with a Payload containing zero bytes +MUST NOT be stored as a retained message on the Server [MQTT-3.3.1-7].

+ +

 

+ +

If the RETAIN flag is 0 in a +PUBLISH packet sent by a Client to a Server, the Server MUST NOT store the message +as a retained message and MUST NOT remove or replace any existing retained +message [MQTT-3.3.1-8].

+ +

 

+ +

If the Server included Retain Available in its CONNACK +response to a Client with its value set to 0 and it receives a PUBLISH packet +with the RETAIN flag is set to 1, then it uses the DISCONNECT Reason Code of +0x9A (Retain not supported) as described in section +4.13.

+ +

 

+ +

When a new Non‑shared Subscription is made, the last +retained message, if any, on each matching topic name is sent to the Client as +directed by the Retain Handling Subscription Option. These messages are sent +with the RETAIN flag set to 1. Which retained messages are sent is controlled +by the Retain Handling Subscription Option. At the time of the Subscription:

+ +

·         +If Retain Handling is set to 0 +the Server MUST send the retained messages matching the Topic Filter of the +subscription to the Client [MQTT-3.3.1-9].

+ +

·         +If Retain Handling is set to 1 then +if the subscription did not already exist, the Server MUST send all retained +message matching the Topic Filter of the subscription to the Client, and if the +subscription did exist the Server MUST NOT send the retained messages. [MQTT-3.3.1-10].

+ +

·         +If Retain Handling is set to 2, +the Server MUST NOT send the retained messages [MQTT-3.3.1-11].

+ +

 

+ +

Refer to section 3.8.3.1 +for a definition of the Subscription Options.

+ +

 

+ +

If the Server receives a PUBLISH packet with the RETAIN flag +set to 1, and QoS 0 it SHOULD store the new QoS 0 message as the new retained +message for that topic, but MAY choose to discard it at any time. If this +happens there will be no retained message for that topic.

+ +

 

+ +

If the current retained message for a Topic expires, it is +discarded and there will be no retained message for that topic.

+ +

 

+ +

The setting of the RETAIN flag in an Application Message +forwarded by the Server from an established connection is controlled by the Retain +As Published subscription option. Refer to section +3.8.3.1 for a definition of the Subscription Options.

+ +

 

+ +

·         +If the value of Retain As +Published subscription option is set to 0, the Server MUST set the RETAIN flag +to 0 when forwarding an Application Message regardless of how the RETAIN flag +was set in the received PUBLISH packet [MQTT-3.3.1-12].

+ +

·         +If the value of Retain As Published +subscription option is set to 1, the Server MUST set the RETAIN flag equal to +the RETAIN flag in the received PUBLISH packet [MQTT-3.3.1-13].

+ +

 

+ +

Non-normative +comment

+ +

Retained messages are useful where +publishers send state messages on an irregular basis. A new non-shared +subscriber will receive the most recent state.

+ +

 

+ +

3.3.1.4 Remaining Length

+ +

This is the length of Variable Header plus the length of the +Payload, encoded as a Variable Byte Integer.

+ +

 

+ +

3.3.2 PUBLISH Variable Header

+ +

The Variable Header of the PUBLISH Packet contains the +following fields in the order: Topic Name, Packet Identifier, and Properties. +The rules for encoding Properties are described in section +2.2.2.

+ +

 

+ +

3.3.2.1 Topic Name

+ +

The Topic Name identifies the information channel to which Payload +data is published.

+ +

 

+ +

The Topic Name MUST be +present as the first field in the PUBLISH packet Variable Header. It MUST be a +UTF-8 Encoded String as defined in section +1.5.4 [MQTT-3.3.2-1].

+ +

 

+ +

The +Topic Name in the PUBLISH packet MUST NOT contain wildcard characters +[MQTT-3.3.2-2].

+ +

 

+ +

The Topic Name in a PUBLISH +packet sent by a Server to a subscribing Client MUST match the Subscription’s +Topic Filter according to the matching process defined in section 4.7 [MQTT-3.3.2-3]. +However, as the Server is permitted to map the Topic Name to another name, it +might not be the same as the Topic Name in the original PUBLISH packet.

+ +

 

+ +

To reduce the size of the PUBLISH packet the sender can use +a Topic Alias. The Topic Alias is described in section +3.3.2.3.4. It is a Protocol Error if the Topic Name is zero length and +there is no Topic Alias.

+ +

 

+ +

3.3.2.2 Packet Identifier

+ +

The Packet Identifier field is only present in PUBLISH packets +where the QoS level is 1 or 2. Section 2.2.1 +provides more information about Packet Identifiers.

+ +

 

+ +

3.3.2.3 PUBLISH Properties

+ +
3.3.2.3.1 Property Length
+ +

The length of the Properties in +the PUBLISH packet Variable Header encoded as a Variable Byte Integer.

+ +

 

+ +
3.3.2.3.2 +Payload Format Indicator
+ +

1 (0x01) Byte, Identifier of the Payload Format +Indicator.

+ +

Followed by the value of the Payload Forma t Indicator, +either of:

+ +

·         +0 (0x00) Byte Indicates that the Payload is unspecified bytes, which +is equivalent to not sending a Payload Format Indicator.

+ +

·         +1 (0x01) Byte Indicates that the Payload is UTF-8 Encoded +Character Data. The UTF-8 data in the Payload MUST be well-formed UTF-8 as defined by the +Unicode specification [Unicode] and restated in RFC 3629 [RFC3629].

+ +

 

+ +

A Server MUST send the +Payload Format Indicator unaltered to all subscribers receiving the Application +Message [MQTT-3.3.2-4]. The receiver MAY +validate that the Payload is of the format indicated, and if it is not send a +PUBACK, PUBREC, or DISCONNECT with Reason Code of 0x99 (Payload format invalid) +as described in section 4.13Refer to section +5.4.9 for information about security issues in +validating the payload format.

+ +

 

+ +
3.3.2.3.3 +Message Expiry Interval`
+ +

2 (0x02) Byte, Identifier of the Message Expiry Interval. +

+ +

Followed by the Four Byte Integer representing the Message Expiry +Interval.

+ +

 

+ +

If present, the Four Byte value is the lifetime of the Application +Message in seconds. If the Message Expiry +Interval has passed and the Server has not managed to start onward delivery to +a matching subscriber, then it MUST delete the copy of the message for that +subscriber [MQTT-3.3.2-5].

+ +

 

+ +

If absent, the Application Message +does not expire.

+ +

 

+ +

The PUBLISH packet sent to a +Client by the Server MUST contain a Message Expiry Interval set to the received +value minus the time that the Application Message has been waiting in the +Server [MQTT-3.3.2-6]. Refer to section 4.1 for details and limitations of stored +state.

+ +

 

+ +
3.3.2.3.4 Topic Alias
+ +

35 (0x23) Byte, Identifier of the Topic Alias.

+ +

Followed by the Two Byte integer representing the Topic +Alias value. It is a Protocol Error to include the Topic Alias value more than +once.

+ +

 

+ +

A Topic Alias is an integer value that is used to identify +the Topic instead of using the Topic Name. This reduces the size of the PUBLISH +packet, and is useful when the Topic Names are long and the same Topic Names +are used repetitively within a Network Connection.

+ +

 

+ +

The sender decides whether to use a Topic Alias and chooses +the value. It sets a Topic Alias mapping by including a non-zero length Topic +Name and a Topic Alias in the PUBLISH packet. The receiver processes the +PUBLISH as normal but also sets the specified Topic Alias mapping to this Topic +Name.

+ +

 

+ +

If a Topic Alias mapping has been set at the receiver, a +sender can send a PUBLISH packet that contains that Topic Alias and a zero length +Topic Name. The receiver then treats the incoming PUBLISH as if it had +contained the Topic Name of the Topic Alias.

+ +

 

+ +

A sender can modify the Topic Alias mapping by sending +another PUBLISH in the same Network Connection with the same Topic Alias value +and a different non-zero length Topic Name.

+ +

 

+ +

Topic Alias mappings exist only within a Network Connection +and last only for the lifetime of that Network Connection. A receiver MUST NOT carry forward any Topic Alias mappings +from one Network Connection to another [MQTT-3.3.2-7].

+ +

 

+ +

A Topic Alias of 0 is not permitted. A sender MUST NOT send a PUBLISH packet containing a Topic Alias which +has the value 0 [MQTT-3.3.2-8].

+ +

 

+ +

A Client MUST NOT send a +PUBLISH packet with a Topic Alias greater than the Topic Alias Maximum value +returned by the Server in the CONNACK packet [MQTT-3.3.2-9]. +A Client MUST accept all Topic Alias values +greater than 0 and less than or equal to the Topic Alias Maximum value that it +sent in the CONNECT packet [MQTT-3.3.2-10]. +

+ +

 

+ +

A Server MUST NOT send a +PUBLISH packet with a Topic Alias greater than the Topic Alias Maximum value +sent by the Client in the CONNECT packet [MQTT-3.3.2-11]. +A Server MUST accept all Topic Alias values +greater than 0 and less than or equal to the Topic Alias Maximum value that it +returned in the CONNACK packet [MQTT-3.3.2-12]. +

+ +

 

+ +

The Topic Alias mappings used by the Client and Server are +independent from each other. Thus, when a Client sends a PUBLISH containing a +Topic Alias value of 1 to a Server and the Server sends a PUBLISH with a Topic +Alias value of 1 to that Client they will in general be referring to different +Topics.

+ +

 

+ +
3.3.2.3.5 +Response Topic
+ +

8 (0x08) +Byte, Identifier of the +Response Topic.

+ +

Followed by a +UTF-8 Encoded String which is used as the Topic Name for a response message. The Response Topic MUST be a UTF-8 Encoded String +as defined in section 1.5.4 [MQTT-3.3.2-13]. The Response Topic MUST NOT contain +wildcard characters [MQTT-3.3.2-14]. It is a Protocol Error to include the Response +Topic more than once. The presence of a Response Topic identifies the Message +as a Request.

+ +

 

+ +

Refer +to section +4.10 for more information about Request +/ Response.

+ +

 

+ +

The Server MUST +send the Response Topic unaltered to all subscribers receiving the Application +Message [MQTT-3.3.2-15].

+ +

 

+ +

Non-normative comment:

+ +

The receiver of an Application Message with a Response Topic +sends a response by using the Response Topic as the Topic Name of a PUBLISH. If +the Request Message contains a Correlation Data, the receiver of the Request +Message should also include this Correlation Data as a property in the PUBLISH +packet of the Response Message.

+ +

 

+ +
3.3.2.3.6 Correlation +Data
+ +

9 (0x09) Byte, Identifier of the Correlation Data.

+ +

Followed by Binary Data. The Correlation Data is used by the +sender of the Request Message to identify which request the Response Message is +for when it is received. It is a Protocol Error to include Correlation Data +more than once. If the Correlation Data is not present, the Requester does not +require any correlation data.

+ +

 

+ +

The +Server MUST send the Correlation Data unaltered to all subscribers receiving +the Application Message [MQTT-3.3.2-16]. +The value of the Correlation Data only has meaning to the sender of the Request +Message and receiver of the Response Message.

+ +

 

+ +

Non-normative +comment

+ +

The receiver of an Application +Message which contains both a Response Topic and a Correlation Data sends a +response by using the Response Topic as the Topic Name of a PUBLISH. The Client +should also send the Correlation Data unaltered as part of the PUBLISH of the +responses.

+ +

 

+ +

Non-normative comment

+ +

If the Correlation Data contains +information which can cause application failures if modified by the Client responding +to the request, it should be encrypted and/or hashed to allow any alteration to +be detected.

+ +

 

+ +

Refer to section 4.10 for +more information about Request / Response

+ +

 

+ +
3.3.2.3.7 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by a UTF-8 String Pair. The User Property is allowed +to appear multiple times to represent multiple name, value pairs. The same name +is allowed to appear more than once.

+ +

 

+ +

The Server MUST send all +User Properties unaltered in a PUBLISH packet when forwarding the Application +Message to a Client [MQTT-3.3.2-17]. The Server MUST maintain the order of User Properties +when forwarding the Application Message [MQTT-3.3.2-18].

+ +

 

+ +

Non-normative +comment

+ +

This property is intended to +provide a means of transferring application layer name-value tags whose meaning +and interpretation are known only by the application programs responsible for +sending and receiving them.

+ +

 

+ +
3.3.2.3.8 Subscription Identifier
+ +

11 (0x0B), +Identifier of the Subscription Identifier.

+ +

Followed by a +Variable Byte Integer representing the identifier of the subscription.

+ +

 

+ +

The Subscription +Identifier can have the value of 1 to 268,435,455. It is a Protocol Error if +the Subscription Identifier has a value of 0. Multiple Subscription Identifiers +will be included if the publication is the result of a match to more than one +subscription, in this case their order is not significant.

+ +

 

+ +
3.3.2.3.9 Content Type
+ +

3 (0x03) +Identifier of the Content Type.

+ +

Followed by a UTF-8 +Encoded String describing the content of the Application Message. The Content Type MUST be a UTF-8 +Encoded String as defined +in section +1.5.4 [MQTT-3.3.2-19].

+ +

It is a Protocol Error to include the Content +Type more than once. The value of the Content Type is defined by the +sending and receiving application.

+ +

 

+ +

A +Server MUST send the Content Type unaltered to all subscribers receiving the Application +Message [MQTT-3.3.2-20].

+ +

 

+ +

Non-normative +comment

+ +

The UTF-8 Encoded String may use a MIME +content type string to describe the contents of the Application message. +However, since the sending and receiving applications are responsible for the +definition and interpretation of the string, MQTT performs no validation of the +string except to insure it is a valid UTF-8 Encoded String.

+ +

 

+ +

Non-normative example

+ +

Figure 3-9 shows an example of a PUBLISH +packet with the Topic Name set to “a/b”, the Packet Identifier set to 10, and +having no properties.

+ +

 

+ +

Figure 3‑9 +- PUBLISH packet Variable Header non-normative example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Topic Name

+
+

byte 1

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Length LSB (3)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 3

+
+

‘a’ (0x61)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 4

+
+

‘/’ (0x2F)

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

1

+
+

1

+
+

1

+
+

byte 5

+
+

‘b’ (0x62)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

Packet Identifier

+
+

byte 6

+
+

Packet Identifier MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 7

+
+

Packet Identifier LSB (10)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

Property Length

+
+

byte 8

+
+

No Properties

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+ +

 

+ +

3.3.3 PUBLISH Payload

+ +

The Payload contains the Application Message that is being +published. The content and format of the data is application specific. The +length of the Payload can be calculated by subtracting the length of the Variable +Header from the Remaining Length field that is in the Fixed Header. It is valid +for a PUBLISH packet to contain a zero length Payload.

+ +

 

+ +

3.3.4 PUBLISH Actions

+ +

The receiver of a PUBLISH +Packet MUST respond with the packet as determined by the QoS in the PUBLISH +Packet [MQTT-3.3.4-1].

+ +

 

+ +

Table 3‑3 Expected PUBLISH packet response

+ + + + + + + + + + + + + + + + + + +
+

QoS Level

+
+

Expected + Response

+
+

QoS 0

+
+

None

+
+

QoS 1

+
+

PUBACK packet

+
+

QoS 2

+
+

PUBREC packet

+
+ +

 

+ +

The Client uses a PUBLISH packet to send an Application +Message to the Server, for distribution to Clients with matching subscriptions.

+ +

 

+ +

The Server uses a PUBLISH packet to send an Application +Message to each Client which has a matching subscription. The PUBLISH packet +includes the Subscription Identifier carried in the SUBSCRIBE packet, if there +was one.

+ +

 

+ +

When Clients make subscriptions with Topic Filters that +include wildcards, it is possible for a Client’s subscriptions to overlap so +that a published message might match multiple filters. In this case the Server MUST deliver the message to the Client respecting +the maximum QoS of all the matching subscriptions [MQTT-3.3.4-2]. In addition, the Server MAY deliver +further copies of the message, one for each additional matching subscription +and respecting the subscription’s QoS in each case.

+ +

 

+ +

If a Client receives an unsolicited Application Message (not +resulting from a subscription) which has a QoS greater than Maximum QoS, it +uses a DISCONNECT packet with Reason Code 0x9B (QoS not supported ) as +described in section 4.13 Handling errors.

+ +

 

+ +

If the Client specified a +Subscription Identifier for any of the overlapping subscriptions the Server +MUST send those Subscription Identifiers in the message which is published as +the result of the subscriptions [MQTT-3.3.4-3]. +If the Server sends a single copy of the +message it MUST include in the PUBLISH packet the Subscription Identifiers for +all matching subscriptions which have a Subscription Identifiers, their order +is not significant [MQTT-3.3.4-4]. If the Server sends multiple PUBLISH packets it MUST +send, in each of them, the Subscription Identifier of the matching subscription +if it has a Subscription Identifier [MQTT-3.3.4-5].

+ +

 

+ +

It is possible that the Client made several subscriptions which +match a publication and that it used the same identifier for more than one of +them. In this case the PUBLISH packet will carry multiple identical Subscription +Identifiers.

+ +

 

+ +

It is a Protocol Error for a PUBLISH packet to contain any Subscription +Identifier other than those received in SUBSCRIBE packet which caused it to +flow. A PUBLISH packet sent from a Client to a Server +MUST NOT contain a Subscription Identifier [MQTT-3.3.4-6].

+ +

 

+ +

If the subscription was shared, then only the Subscription Identifiers +that were present in the SUBSCRIBE packet from the Client which is receiving +the message are returned in the PUBLISH packet.

+ +

 

+ +

The action of the recipient when it receives a PUBLISH packet +depends on the QoS level as described in section +4.3.

+ +

 

+ +

If the PUBLISH packet contains a Topic Alias, the receiver +processes it as follows:

+ +

1)    A Topic Alias +value of 0 or greater than the Maximum Topic Alias is a Protocol Error, the +receiver uses DISCONNECT with Reason Code of 0x94 (Topic Alias invalid) as +described in section 4.13.

+ +

2)    If the receiver +has already established a mapping for the Topic Alias, then

+ +

a)    If the packet +has a zero length Topic Name, the receiver processes it using the Topic Name +that corresponds to the Topic Alias

+ +

b)    If the packet +contains a non-zero length Topic Name, the receiver processes the packet using +that Topic Name and updates its mapping for the Topic Alias to the Topic Name +from the incoming packet
+
+

+ +

3)    If the receiver +does not already have a mapping for this Topic Alias

+ +

a)    If the packet +has a zero length Topic Name field it is a Protocol Error and the receiver uses +DISCONNECT with Reason Code of 0x82 (Protocol Error) as described in section 4.13.

+ +

b)    If the packet +contains a Topic Name with a non-zero length, the receiver processes the packet +using that Topic Name and sets its mappings for the Topic Alias to Topic Name +from the incoming packet.

+ +

 

+ +

Non-normative Comment

+ +

If the Server distributes +Application Messages to Clients at different protocol levels (such as MQTT +V3.1.1) which do not support properties or other features provided by this specification, +some information in the Application Message can be lost, and applications which +depend on this information might not work correctly.

+ +

 

+ +

The Client MUST NOT send +more than Receive Maximum QoS 1 and QoS 2 PUBLISH packets for which it has not +received PUBACK, PUBCOMP, or PUBREC with a Reason Code of 128 or greater from +the Server [MQTT-3.3.4-7]. If it receives +more than Receive Maximum QoS 1 and QoS 2 PUBLISH packets where it has not sent +a PUBACK or PUBCOMP in response, the Server uses a DISCONNECT packet with +Reason Code 0x93 (Receive Maximum exceeded) as described in section 4.13 Handling errors. Refer to section 4.9 for more information about flow control.

+ +

 

+ +

The Client MUST NOT delay +the sending of any packets other than PUBLISH packets due to having sent +Receive Maximum PUBLISH packets without receiving acknowledgements for them +[MQTT-3.3.4-8]. The value of Receive Maximum +applies only to the current Network Connection.

+ +

 

+ +

Non-normative comment

+ +

The Client might choose to send +fewer than Receive Maximum messages to the Server without receiving +acknowledgement, even if it has more than this number of messages available to +send.

+ +

 

+ +

Non-normative comment

+ +

The Client might choose to suspend +the sending of QoS 0 PUBLISH packets when it suspends the sending of QoS 1 and +QoS 2 PUBLISH packets.

+ +

 

+ +

Non-normative comment

+ +

If the Client sends QoS 1 or QoS 2 +PUBLISH packets before it has received a CONNACK packet, it risks being disconnected +because it has sent more than Receive Maximum publications.

+ +

 

+ +

The Server MUST NOT send +more than Receive Maximum QoS 1 and QoS 2 PUBLISH packets for which it has not +received PUBACK, PUBCOMP, or PUBREC with a Reason Code of 128 or greater from +the Client [MQTT-3.3.4-9]. If it receives +more than Receive Maximum QoS 1 and QoS 2 PUBLISH packets where it has not sent +a PUBACK or PUBCOMP in response, the Client uses DISCONNECT with Reason Code +0x93 (Receive Maximum exceeded) as described in section +4.13 Handling errors. Refer to section 4.9 for +more information about flow control.

+ +

 

+ +

The Server MUST NOT delay +the sending of any packets other than PUBLISH packets due to having sent +Receive Maximum PUBLISH packets without receiving acknowledgements for them +[MQTT-3.3.4-10].

+ +

 

+ +

Non-normative comment

+ +

The Server might choose to send +fewer than Receive Maximum messages to the Client without receiving +acknowledgement, even if it has more than this number of messages available to +send.

+ +

 

+ +

Non-normative comment

+ +

The Server might choose to suspend +the sending of QoS 0 PUBLISH packets when it suspends the sending of QoS 1 and +QoS 2 PUBLISH packets.

+ +

 

+ +

3.4 +PUBACK – Publish acknowledgement

+ +

A PUBACK packet is the response to a PUBLISH packet with QoS +1.

+ +

 

+ +

3.4.1 PUBACK Fixed Header

+ +

Figure 3‑10 - PUBACK packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (4)

+
+

Reserved

+
+

 

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable Header, encoded as a Variable +Byte Integer.

+ +

 

+ +

3.4.2 PUBACK Variable Header

+ +

The Variable Header of the PUBACK Packet contains the +following fields in the order: Packet Identifier from the PUBLISH packet that +is being acknowledged, PUBACK Reason Code, Property Length, and the Properties. +The rules for encoding Properties are described in section +2.2.2.

+ +

 

+ +

Figure 3‑11 +– PUBACK packet Variable Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

Packet Identifier + MSB

+
+

byte 2

+
+

Packet Identifier + LSB

+
+

byte 3

+
+

PUBACK Reason Code

+
+

byte 4

+
+

Property Length

+
+ +

 

+ +

3.4.2.1 PUBACK Reason Code

+ +

Byte 3 in the Variable Header is the PUBACK Reason Code. If +the Remaining Length is 2, then there is no Reason Code and the value of 0x00 +(Success) is used.

+ +

 

+ +

Table 3‑4 - PUBACK Reason Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

The message is accepted. Publication of the QoS 1 message + proceeds.

+
+

16

+
+

0x10

+
+

No matching subscribers

+
+

The message is accepted but there are no subscribers. This + is sent only by the Server. If the Server knows that there are no matching + subscribers, it MAY use this Reason Code instead of 0x00 (Success).

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

The receiver does not accept the publish but either does + not want to reveal the reason, or it does not match one of the other values.

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

The PUBLISH is valid but the receiver is not willing to + accept it.

+
+

135

+
+

0x87

+
+

Not authorized

+
+

The PUBLISH is not authorized.

+
+

144

+
+

0x90

+
+

Topic Name invalid

+
+

The Topic Name is not malformed, but is not accepted by + this Client or Server.

+
+

145

+
+

0x91

+
+

Packet identifier in use

+
+

The Packet Identifier is already in use. This might + indicate a mismatch in the Session State between the Client and Server.

+
+

151

+
+

0x97

+
+

Quota exceeded

+
+

An implementation or administrative imposed limit has been + exceeded.

+
+

153

+
+

0x99

+
+

Payload format invalid

+
+

The payload format does not match the specified Payload + Format Indicator.

+
+ +

 

+ +

The Client or Server sending +the PUBACK packet MUST use one of the PUBACK Reason Codes [MQTT-3.4.2-1]. The Reason Code and Property Length +can be omitted if the Reason Code is 0x00 (Success) and there are no +Properties. In this case the PUBACK has a Remaining Length of 2.

+ +

 

+ +

3.4.2.2 PUBACK Properties

+ +
3.4.2.2.1 +Property Length
+ +

The length of the Properties in the PUBACK packet Variable +Header encoded as a Variable Byte Integer. If the Remaining Length is less than +4 there is no Property Length and the value of 0 is used.

+ +

 

+ +
3.4.2.2.2 +Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is a human readable string +designed for diagnostics and is not intended to be parsed by the receiver.

+ +

 

+ +

The sender uses this value to give additional information to +the receiver. The sender MUST NOT send this +property if it would increase the size of the PUBACK packet beyond the Maximum +Packet Size specified by the receiver [MQTT-3.4.2-2]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.4.2.2.3 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property can be used to +provide additional diagnostic or other information. The sender MUST NOT send this property if it would increase the size of +the PUBACK packet beyond the Maximum Packet Size specified by the receiver +[MQTT-3.4.2-3]. The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

3.4.3 PUBACK Payload

+ +

The PUBACK packet has no Payload.

+ +

 

+ +

3.4.4 PUBACK Actions

+ +

This is described in section 4.3.2.

+ +

 

+ +

3.5 PUBREC – Publish received +(QoS 2 delivery part 1)

+ +

A PUBREC packet is the response to a PUBLISH packet with QoS +2. It is the second packet of the QoS 2 protocol exchange.

+ +

 

+ +

3.5.1 PUBREC Fixed Header

+ +

Figure 3‑12 +- PUBREC packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (5)

+
+

Reserved

+
+

 

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable +Header, encoded as a Variable Byte Integer.

+ +

 

+ +

3.5.2 PUBREC Variable Header

+ +

The Variable Header of the PUBREC Packet consists of the +following fields in the order: the Packet Identifier from the PUBLISH packet +that is being acknowledged, PUBREC Reason Code, and Properties. The rules for +encoding Properties are described in section 2.2.2.

+ +

 

+ +

 Figure +3‑13 - PUBREC packet Variable Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

Packet Identifier + MSB

+
+

byte 2

+
+

Packet Identifier + LSB

+
+

byte 3

+
+

PUBREC Reason Code

+
+

byte 4

+
+

Property Length

+
+ +

 

+ +

3.5.2.1 PUBREC Reason Code

+ +

Byte 3 in the Variable Header is the PUBREC Reason Code. If +the Remaining Length is 2, then the Publish Reason Code has the value 0x00 +(Success).

+ +

 

+ +

Table 3‑5 – PUBREC Reason Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

The message is accepted. Publication of the QoS 2 message + proceeds.

+
+

16

+
+

0x10

+
+

No matching subscribers.

+
+

The message is accepted but there are no subscribers. This + is sent only by the Server. If the Server knows that there are no matching + subscribers, it MAY use this Reason Code instead of 0x00 (Success).

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

The receiver does not accept the publish but either does + not want to reveal the reason, or it does not match one of the other values.

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

The PUBLISH is valid but the receiver is not willing to + accept it.

+
+

135

+
+

0x87

+
+

Not authorized

+
+

The PUBLISH is not authorized.

+
+

144

+
+

0x90

+
+

Topic Name invalid

+
+

The Topic Name is not malformed, but is not accepted by + this Client or Server.

+
+

145

+
+

0x91

+
+

Packet Identifier in use

+
+

The Packet Identifier is already in use. This might + indicate a mismatch in the Session State between the Client and Server.

+
+

151

+
+

0x97

+
+

Quota exceeded

+
+

An implementation or administrative imposed limit has been + exceeded.

+
+

153

+
+

0x99

+
+

Payload format invalid

+
+

The payload format does not match the one specified in the + Payload Format Indicator.

+
+ +

 

+ +

The Client or Server sending +the PUBREC packet MUST use one of the PUBREC Reason Code values. [MQTT-3.5.2-1]. The Reason Code and Property Length +can be omitted if the Reason Code is 0x00 (Success) and there are no +Properties. In this case the PUBREC has a Remaining Length of 2.

+ +

 

+ +

3.5.2.2 PUBREC Properties

+ +
3.5.2.2.1 +Property Length
+ +

The length of the Properties in the PUBREC packet Variable +Header encoded as a Variable Byte Integer. If the Remaining Length is less than +4 there is no Property Length and the value of 0 is used.

+ +

 

+ +
3.5.2.2.2 +Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is human readable, designed +for diagnostics and SHOULD NOT be parsed by the receiver.

+ +

 

+ +

The sender uses this value to give additional information to +the receiver. The sender MUST NOT send this +property if it would increase the size of the PUBREC packet beyond the Maximum +Packet Size specified by the receiver [MQTT-3.5.2-2]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.5.2.2.3 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property can be used to provide +additional diagnostic or other information. The +sender MUST NOT send this property if it would increase the size of the PUBREC packet +beyond the Maximum Packet Size specified by the receiver [MQTT-3.5.2-3]. The User Property is allowed to appear +multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

3.5.3 PUBREC Payload

+ +

The PUBREC packet has no Payload.

+ +

3.5.4 PUBREC Actions

+ +

This is described in section 4.3.3.

+ +

 

+ +

3.6 PUBREL – Publish release +(QoS 2 delivery part 2)

+ +

A PUBREL packet is the response to a PUBREC packet. It is +the third packet of the QoS 2 protocol exchange.

+ +

 

+ +

3.6.1 PUBREL Fixed Header

+ +

Figure 3‑14 +– PUBREL packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (6)

+
+

Reserved

+
+

 

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Bits 3,2,1 and 0 of the +Fixed Header in the PUBREL packet are reserved and MUST be set to 0,0,1 and 0 +respectively. The Server MUST treat any other value as malformed and close the +Network Connection [MQTT-3.6.1-1].

+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable +Header, encoded as a Variable Byte Integer.

+ +

 

+ +

3.6.2 PUBREL Variable Header

+ +

The Variable Header of the PUBREL Packet contains the +following fields in the order: the Packet Identifier from the PUBREC packet +that is being acknowledged, PUBREL Reason Code, and Properties. The rules for +encoding Properties are described in section 2.2.2.

+ +

 

+ +

 Figure +3‑15 – PUBREL packet Variable Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

Packet Identifier + MSB

+
+

byte 2

+
+

Packet Identifier + LSB

+
+

byte 3

+
+

PUBREL Reason Code

+
+

byte 4

+
+

Property Length

+
+ +

 

+ +

3.6.2.1 PUBREL Reason Code

+ +

Byte 3 in the Variable Header is the PUBREL Reason Code. If +the Remaining Length is 2, the value of 0x00 (Success) is used.

+ +

 

+ +

Table 3‑6 - PUBREL Reason Codes

+ + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

Message released.

+
+

146

+
+

0x92

+
+

Packet Identifier not found

+
+

The Packet Identifier is not known. This is not an error + during recovery, but at other times indicates a mismatch between the Session + State on the Client and Server.

+
+ +

 

+ +

The Client or Server sending +the PUBREL packet MUST use one of the PUBREL Reason Code values [MQTT-3.6.2-1]. The Reason Code and Property Length +can be omitted if the Reason Code is 0x00 (Success) and there are no +Properties. In this case the PUBREL has a Remaining Length of 2.

+ +

 

+ +

3.6.2.2 PUBREL Properties

+ +
3.6.2.2.1 Property Length
+ +

The length of the Properties in the PUBREL packet Variable +Header encoded as a Variable Byte Integer. If the Remaining Length is less than +4 there is no Property Length and the value of 0 is used.

+ +

 

+ +
3.6.2.2.2 +Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is human readable, designed +for diagnostics and SHOULD NOT be parsed by the receiver.

+ +

 

+ +

The sender uses this value to give additional information to +the receiver. The sender MUST NOT send this +Property if it would increase the size of the PUBREL packet beyond the Maximum +Packet Size specified by the receiver [MQTT-3.6.2-2]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.6.2.2.3 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property can be used to +provide additional diagnostic or other information for the PUBREL. The sender MUST NOT send this property if it would +increase the size of the PUBREL packet beyond the Maximum Packet Size specified +by the receiver [MQTT-3.6.2-3]. The User +Property is allowed to appear multiple times to represent multiple name, value +pairs. The same name is allowed to appear more than once.

+ +

 

+ +

3.6.3 PUBREL Payload

+ +

The PUBREL packet has no Payload.

+ +

 

+ +

3.6.4 PUBREL Actions

+ +

This is described in section 4.3.3.

+ +

 

+ +

3.7 PUBCOMP – Publish complete +(QoS 2 delivery part 3)

+ +

The PUBCOMP packet is the response to a PUBREL packet. It is +the fourth and final packet of the QoS 2 protocol exchange.

+ +

 

+ +

3.7.1 PUBCOMP Fixed Header

+ +

Figure 3‑16 +– PUBCOMP packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control packet + type (7)

+
+

Reserved

+
+

 

+
+

0

+
+

1

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable +Header, encoded as a Variable Byte Integer.

+ +

 

+ +

3.7.2 PUBCOMP Variable Header

+ +

The Variable Header of the PUBCOMP Packet contains the +following fields in the order: Packet Identifier from the PUBREL packet that is +being acknowledged, PUBCOMP Reason Code, and Properties. The rules for encoding +Properties are described in section 2.2.2.

+ +

 

+ +

Figure +3‑17 - PUBCOMP packet Variable Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

Packet Identifier + MSB

+
+

byte 2

+
+

Packet Identifier + LSB

+
+

byte 3

+
+

PUBCOMP Reason Code

+
+

byte 4

+
+

Property Length

+
+ +

 

+ +

3.7.2.1 PUBCOMP Reason Code

+ +

Byte 3 in the Variable Header is the PUBCOMP Reason Code. If +the Remaining Length is 2, then the value 0x00 (Success) is used.

+ +

 

+ +

Table 3‑7 +– PUBCOMP Reason Codes

+ + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

Packet Identifier released. Publication of QoS 2 message + is complete.

+
+

146

+
+

0x92

+
+

Packet Identifier not found

+
+

The Packet Identifier is not known. This is not an error + during recovery, but at other times indicates a mismatch between the Session + State on the Client and Server.

+
+ +

 

+ +

The Client or Server sending +the PUBCOMP packet MUST use one of the PUBCOMP Reason Code values [MQTT-3.7.2-1]. The Reason Code and Property Length +can be omitted if the Reason Code is 0x00 (Success) and there are no +Properties. In this case the PUBCOMP has a Remaining Length of 2.

+ +

 

+ +

3.7.2.2 PUBCOMP Properties

+ +
3.7.2.2.1 Property Length
+ +

The length of the Properties in the PUBCOMP packet Variable +Header encoded as a Variable Byte Integer. If the Remaining Length is less than +4 there is no Property Length and the value of 0 is used.

+ +

 

+ +
3.7.2.2.2 +Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is a human readable string +designed for diagnostics and SHOULD NOT be parsed by the receiver.

+ +

 

+ +

The sender uses this value to give additional information to +the receiver. The sender MUST NOT send this +Property if it would increase the size of the PUBCOMP packet beyond the Maximum +Packet Size specified by the receiver [MQTT-3.7.2-2]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.7.2.2.3 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property can be used to +provide additional diagnostic or other information. The sender MUST NOT send this property if it would increase the size of +the PUBCOMP packet beyond the Maximum Packet Size specified by the receiver +[MQTT-3.7.2-3]. The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

3.7.3 +PUBCOMP Payload

+ +

The PUBCOMP packet has no Payload.

+ +

 

+ +

3.7.4 PUBCOMP Actions

+ +

This is described in section 4.3.3.

+ +

 

+ +

3.8 SUBSCRIBE - Subscribe request

+ +

The SUBSCRIBE packet is sent from the Client to the Server +to create one or more Subscriptions. Each Subscription registers a Client’s +interest in one or more Topics. The Server sends PUBLISH packets to the Client +to forward Application Messages that were published to Topics that match these +Subscriptions. The SUBSCRIBE packet also specifies (for each Subscription) the +maximum QoS with which the Server can send Application Messages to the Client.

+ +

 

+ +

3.8.1 SUBSCRIBE Fixed Header

+ +

Figure 3‑18 +SUBSCRIBE packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (8)

+
+

Reserved

+
+

 

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Bits 3,2,1 and 0 of the +Fixed Header of the SUBSCRIBE packet are reserved and MUST be set to 0,0,1 and +0 respectively. The Server MUST treat any other value as malformed and close +the Network Connection [MQTT-3.8.1-1].

+ +

 

+ +

Remaining Length field

+ +

This is the length of Variable +Header plus the length of the Payload, encoded as a Variable Byte Integer.

+ +

 

+ +

3.8.2 SUBSCRIBE Variable +Header

+ +

The Variable Header of the SUBSCRIBE Packet contains the +following fields in the order: Packet Identifier, and Properties. Section 2.2.1 provides more information about Packet +Identifiers. The rules for encoding Properties are described in section 2.2.2.

+ +

 

+ +

Non-normative example

+ +

Figure 3-19 shows an example of a +SUBSCRIBE variable header with a Packet Identifier of 10 and no properties.

+ +

 

+ +

Figure +3‑19 – SUBSCRIBE Variable Header example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Packet Identifier

+
+

byte 1

+
+

Packet Identifier MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Packet Identifier LSB (10)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

0

+
+

byte 3

+
+

Property Length (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+ +

 

+ +

3.8.2.1 SUBSCRIBE Properties

+ +
3.8.2.1.1 Property Length
+ +

The length of Properties in the SUBSCRIBE packet Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +
3.8.2.1.2 Subscription Identifier
+ +

11 (0x0B) Byte, Identifier of the Subscription +Identifier.

+ +

Followed by a Variable Byte Integer representing the +identifier of the subscription. The Subscription Identifier can have the value +of 1 to 268,435,455. It is a Protocol Error if the Subscription Identifier has +a value of 0. It is a Protocol Error to include the Subscription Identifier +more than once.

+ +

 

+ +

The Subscription Identifier is associated with any +subscription created or modified as the result of this SUBSCRIBE packet. If +there is a Subscription Identifier, it is stored with the subscription. If this +property is not specified, then the absence of a Subscription Identifier is +stored with the subscription.

+ +

 

+ +

Refer to section 3.8.3.1 +for more information about the handling of Subscription Identifiers.

+ +

 

+ +
3.8.2.1.3 User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by a UTF-8 String Pair.

+ +

 

+ +

The User Property is allowed to appear multiple times to +represent multiple name, value pairs. The same name is allowed to appear more +than once.

+ +

 

+ +

Non-normative comment

+ +

User Properties on the SUBSCRIBE +packet can be used to send subscription related properties from the Client to +the Server. The meaning of these properties is not defined by this specification.

+ +

 

+ +

3.8.3 SUBSCRIBE Payload

+ +

The Payload of a SUBSCRIBE packet contains a list of Topic +Filters indicating the Topics to which the Client wants to subscribe. The Topic Filters MUST be a UTF-8 Encoded String +[MQTT-3.8.3-1]. Each Topic Filter is followed by +a Subscription Options byte.

+ +

 

+ +

The Payload MUST contain at least +one Topic Filter and Subscription Options pair [MQTT-3.8.3-2]. +A SUBSCRIBE packet with no Payload is a Protocol Error. Refer to section 4.13 for information about handling errors.

+ +

 

+ +

3.8.3.1 Subscription +Options

+ +

Bits 0 and 1 of the Subscription Options represent Maximum +QoS field. This gives the maximum QoS level at which the Server can send +Application Messages to the Client. It is a Protocol Error if the Maximum QoS field +has the value 3.

+ +

 

+ +

Bit 2 of the +Subscription Options represents the No Local option. If the value is 1, +Application Messages MUST NOT be forwarded to a connection with a ClientID +equal to the ClientID of the publishing connection [MQTT-3.8.3-3]. It is a Protocol Error to +set the No Local bit to 1 on a Shared Subscription [MQTT-3.8.3-4].

+ +

 

+ +

Bit 3 of the Subscription Options represents the Retain As Published option. If 1, Application Messages +forwarded using this subscription keep the RETAIN flag they were published +with. If 0, Application Messages forwarded using this subscription have the +RETAIN flag set to 0. Retained messages sent when the subscription is +established have the RETAIN flag set to 1.

+ +

 

+ +

Bits 4 and 5 of the Subscription +Options represent the Retain Handling option. This option specifies whether +retained messages are sent when the subscription is established. This does not +affect the sending of retained messages at any point after the subscribe. If +there are no retained messages matching the Topic Filter, all of these values +act the same. The values are:

+ +

0 = Send retained messages at the +time of the subscribe

+ +

1 = Send retained messages at +subscribe only if the subscription does not currently exist

+ +

2 = Do not send retained messages +at the time of the subscribe

+ +

It is a Protocol Error to send a +Retain Handling value of 3.

+ +

 

+ +

Bits 6 and 7 of the Subscription Options byte are reserved +for future use. The Server MUST treat a +SUBSCRIBE packet as malformed if any of Reserved bits in the Payload are +non-zero [MQTT-3.8.3-5].

+ +

 

+ +

Non-normative +comment

+ +

The No +Local and Retain As Published subscription options can be used to implement +bridging where the Client is sending the message on to another Server.

+ +

 

+ +

Non-normative comment

+ +

Not +sending retained messages for an existing subscription is useful when a +reconnect is done and the Client is not certain whether the subscriptions were +completed in the previous connection to the Session.

+ +

 

+ +

Non-normative comment

+ +

Not +sending stored retained messages because of a new subscription is useful where +a Client wishes to receive change notifications and does not need to know the +initial state.

+ +

 

+ +

Non-normative comment

+ +

For a +Server that indicates it does not support retained messages, all valid values +of Retain As Published and Retain Handling give the same result which is to not +send any retained messages at subscribe and to set the RETAIN flag to 0 for all +messages.

+ +

 

+ +

Figure +3‑20– SUBSCRIBE packet Payload format

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Topic Filter

+
+

byte 1

+
+

Length MSB

+
+

byte 2

+
+

Length LSB

+
+

bytes 3..N

+
+

Topic Filter

+
+

Subscription Options

+
+

 

+
+

Reserved

+
+

Retain Handling

+
+

RAP

+
+

NL

+
+

QoS

+
+

byte N+1

+
+

0

+
+

0

+
+

X

+
+

X

+
+

X

+
+

X

+
+

X

+
+

X

+
+ +

RAP means Retain as Published.

+ +

NL means No Local.

+ +

 

+ +

Non-normative +example

+ +

Figure 3.21 show the SUBSCRIBE +Payload example with two Topic Filters. The first is “a/b” with QoS 1, and the +second is “c/d” with QoS 2.

+ +

+ +

Figure 3‑21 +- Payload byte format non-normative example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Topic Filter

+
+

byte 1

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Length LSB (3)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 3

+
+

‘a’ (0x61)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 4

+
+

‘/’ (0x2F)

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

1

+
+

1

+
+

1

+
+

byte 5

+
+

‘b’ (0x62)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

Subscription Options

+
+

byte 6

+
+

Subscription Options + (1)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

Topic Filter

+
+

byte 7

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 8

+
+

Length LSB (3)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 9

+
+

‘c’ (0x63)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 10

+
+

‘/’ (0x2F)

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

1

+
+

1

+
+

1

+
+

byte 11

+
+

‘d’ (0x64)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

Subscription Options

+
+

byte 12

+
+

Subscription + Options (2)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+ +

 

+ +

3.8.4 +SUBSCRIBE Actions

+ +

When the Server receives a +SUBSCRIBE packet from a Client, the Server MUST respond with a SUBACK packet +[MQTT-3.8.4-1]. The +SUBACK packet MUST have the same Packet Identifier as the SUBSCRIBE packet that +it is acknowledging [MQTT-3.8.4-2].

+ +

 

+ +

The Server is permitted to start sending PUBLISH packets +matching the Subscription before the Server sends the SUBACK packet.

+ +

 

+ +

If a Server receives a +SUBSCRIBE packet containing a Topic Filter that is identical to a Non‑shared +Subscription’s Topic Filter for the current Session, then it MUST replace that +existing Subscription with a new Subscription [MQTT-3.8.4-3]. +The Topic Filter in the new Subscription will be identical to that in the +previous Subscription, although its Subscription Options could be different. If the Retain Handling option is 0, any existing +retained messages matching the Topic Filter MUST be re-sent, but Applicaton +Messages MUST NOT be lost due to replacing the Subscription [MQTT-3.8.4-4].

+ +

 

+ +

If a Server receives a Non‑shared Topic Filter that is +not identical to any Topic Filter for the current Session, a new Non-shared +Subscription is created. If the Retain Handling option is not 2, all matching +retained messages are sent to the Client.

+ +

 

+ +

If a Server receives a Topic Filter that is identical to the +Topic Filter for a Shared Subscription that already exists on the Server, the +Session is added as a subscriber to that Shared Subscription. No retained +messages are sent.

+ +

 

+ +

If a Server receives a Shared Subscription Topic Filter that +is not identical to any existing Shared Subscription’s Topic Filter, a new +Shared Subscription is created. The Session is added as a subscriber to that +Shared Subscription. No retained messages are sent.

+ +

 

+ +

Refer to section 4.8 for more details on Shared +Subscriptions.

+ +

 

+ +

If a Server receives a +SUBSCRIBE packet that contains multiple Topic Filters it MUST handle that +packet as if it had received a sequence of multiple SUBSCRIBE packets, except +that it combines their responses into a single SUBACK response [MQTT-3.8.4-5].

+ +

 

+ +

The SUBACK packet sent by +the Server to the Client MUST contain a Reason Code for each Topic +Filter/Subscription Option pair [MQTT-3.8.4-6]. +This Reason Code MUST either show the maximum +QoS that was granted for that Subscription or indicate that the subscription +failed [MQTT-3.8.4-7]. The Server might grant a lower Maximum QoS than +the subscriber requested. The QoS of Application +Messages sent in response to a Subscription MUST be the minimum of the QoS of +the originally published message and the Maximum QoS granted by the Server +[MQTT-3.8.4-8]. The server is permitted to send +duplicate copies of a message to a subscriber in the case where the original message +was published with QoS 1 and the maximum QoS granted was QoS 0.

+ +

 

+ +

Non-normative comment

+ +

If a subscribing Client has been +granted maximum QoS 1 for a particular Topic Filter, then a QoS 0 Application +Message matching the filter is delivered to the Client at QoS 0. This means +that at most one copy of the message is received by the Client. On the other +hand, a QoS 2 Message published to the same topic is downgraded by the Server +to QoS 1 for delivery to the Client, so that Client might receive duplicate +copies of the Message.

+ +

 

+ +

Non-normative comment

+ +

If the subscribing Client has been +granted maximum QoS 0, then an Application Message originally published as QoS +2 might get lost on the hop to the Client, but the Server should never send a +duplicate of that Message. A QoS 1 Message published to the same topic might +either get lost or duplicated on its transmission to that Client.

+ +

 

+ +

Non-normative +comment

+ +

Subscribing to a Topic Filter at +QoS 2 is equivalent to saying "I would like to receive Messages matching this +filter at the QoS with which they were published". This means a publisher +is responsible for determining the maximum QoS a Message can be delivered at, +but a subscriber is able to require that the Server downgrades the QoS to one +more suitable for its usage.

+ +

 

+ +

The Subscription Identifiers are part of the Session State +in the Server and are returned to the Client receiving a matching PUBLISH +packet. They are removed from the Server’s Session State when the Server +receives an UNSUBSCRIBE packet, when the Server receives a SUBSCRIBE packet +from the Client for the same Topic Filter but with a different Subscription Identifier +or with no Subscription Identifier, or when the Server sends Session Present 0 +in a CONNACK packet.

+ +

 

+ +

The Subscription Identifiers do not form part of the Client’s +Session State in the Client. In a useful implementation, a Client will +associate the Subscription Identifiers with other Client side state, this state +is typically removed when the Client unsubscribes, when the Client subscribes +for the same Topic Filter with a different identifier or no identifier, or when +the Client receives Session Present 0 in a CONNACK packet.

+ +

 

+ +

The Server need not use the same set of Subscription Identifiers +in the retransmitted PUBLISH packet. The Client can remake a Subscription by +sending a SUBSCRIBE packet containing a Topic Filter that is identical to the +Topic Filter of an existing Subscription in the current Session. If the Client +remade a subscription after the initial transmission of a PUBLISH packet and used +a different Subscription Identifier, then the Server is allowed to use the +identifiers from the first transmission in any retransmission. Alternatively, +the Server is allowed to use the new identifiers during a retransmission. The Server +is not allowed to revert to the old identifier after it has sent a PUBLISH +packet containing the new one.

+ +

 

+ +

Non-normative +comment

+ +

Usage scenarios, for illustration of +Subscription Identifiers.

+ +

·         +The Client implementation indicates via its programming interface +that a publication matched more than one subscription. The Client implementation +generates a new identifier each time a subscription is made. If the returned +publication carries more than one Subscription Identifier, then the publication +matched more than one subscription.
+
+

+ +

·         +The Client implementation allows the subscriber to direct +messages to a callback associated with the subscription. The Client implementation +generates an identifier which uniquely maps the identifier to the callback. +When a publication is received it uses the Subscription Identifier to determine +which callback is driven.
+
+

+ +

·         +The Client implementation returns the topic string used to make the +subscription to the application when it delivers the published message. To +achieve this the Client generates an identifier which uniquely identifies the Topic +Filter. When a publication is received the Client implementation uses the +identifiers to look up the original Topic Filters and return them to the Client +application.
+
+

+ +

·         +A gateway forwards publications received from a Server to Clients +that have made subscriptions to the gateway. The gateway implementation maintains +a map of each unique Topic Filter it receives to the set of ClientID, Subscription +Identifier pairs that it also received. It generates a unique identifier for each +Topic Filter that it forwards to the Server. When a publication is received, +the gateway uses the Subscription Identifiers it received from the Server to +look up the Client Identifier, Subscription Identifier pairs associated with +them. It adds these to the PUBLISH packets it sends to the Clients. If the +upstream Server sent multiple PUBLISH packets because the message matched +multiple subscriptions, then this behavior is mirrored to the Clients.

+ +

 

+ +

3.9 SUBACK – Subscribe +acknowledgement

+ +

A SUBACK packet is sent by the Server to the Client to +confirm receipt and processing of a SUBSCRIBE packet.

+ +

 

+ +

A SUBACK packet contains a list of Reason Codes, that +specify the maximum QoS level that was granted or the error which was found for +each Subscription that was requested by the SUBSCRIBE.

+ +

 

+ +

3.9.1 SUBACK Fixed Header

+ +

Figure 3‑22 +- SUBACK Packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (9)

+
+

Reserved

+
+

 

+
+

1

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of Variable Header plus the length of the +Payload, encoded as a Variable Byte Integer.

+ +

 

+ +

3.9.2 SUBACK Variable Header

+ +

The Variable Header of the SUBACK Packet contains the following +fields in the order: the Packet Identifier from the SUBSCRIBE Packet that is +being acknowledged, and Properties.

+ +

 

+ +

3.9.2.1 SUBACK Properties

+ +
3.9.2.1.1 Property Length
+ +

The length of Properties in the SUBACK packet Variable +Header encoded as a Variable Byte Integer

+ +

 

+ +
3.9.2.1.2 +Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is a human readable string +designed for diagnostics and SHOULD NOT be parsed by the Client.

+ +

 

+ +

The Server uses this value to give additional information to +the Client. The Server MUST NOT send this +Property if it would increase the size of the SUBACK packet beyond the Maximum +Packet Size specified by the Client [MQTT-3.9.2-1]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.9.2.1.3 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property can be used to +provide additional diagnostic or other information. The Server MUST NOT send this property if it would increase the size of +the SUBACK packet beyond the Maximum Packet Size specified by Client [MQTT-3.9.2-2]. The User Property is allowed to appear +multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

+ +

Figure 3‑23 SUBACK packet Variable Header

+ + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

Packet Identifier + MSB

+
+

byte 2

+
+

Packet Identifier + LSB

+
+ +

 

+ +

3.9.3 +SUBACK Payload

+ +

The Payload contains a list of Reason Codes. Each Reason +Code corresponds to a Topic Filter in the SUBSCRIBE packet being acknowledged. The order of Reason Codes in the SUBACK packet MUST +match the order of Topic Filters in the SUBSCRIBE packet [MQTT-3.9.3-1].

+ +

 

+ +

Table 3‑8 - Subscribe Reason Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Granted QoS 0

+
+

The subscription is accepted and the maximum QoS sent will + be QoS 0. This might be a lower QoS than was requested.

+
+

1

+
+

0x01

+
+

Granted QoS 1

+
+

The subscription is accepted and the maximum QoS sent will + be QoS 1. This might be a lower QoS than was requested.

+
+

2

+
+

0x02

+
+

Granted QoS 2

+
+

The subscription is accepted and any received QoS will be + sent to this subscription.

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

The subscription is not accepted and the Server either + does not wish to reveal the reason or none of the other Reason Codes apply.

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

The SUBSCRIBE is valid but the Server does not accept it.

+
+

135

+
+

0x87

+
+

Not authorized

+
+

The Client is not authorized to make this subscription.

+
+

143

+
+

0x8F

+
+

Topic Filter invalid

+
+

The Topic Filter is correctly formed but is not allowed + for this Client.

+
+

145

+
+

0x91

+
+

Packet Identifier in use

+
+

The specified Packet Identifier is already in use.

+
+

151

+
+

0x97

+
+

Quota exceeded

+
+

An implementation or administrative imposed limit has been + exceeded.

+
+

158

+
+

0x9E

+
+

Shared Subscriptions not + supported

+
+

The Server does not support Shared Subscriptions for this Client.

+
+

161

+
+

0xA1

+
+

Subscription Identifiers not + supported

+
+

The Server does not support Subscription Identifiers; the + subscription is not accepted.

+
+

162

+
+

0xA2

+
+

Wildcard Subscriptions not + supported

+
+

The Server does not support Wildcard Subscriptions; the + subscription is not accepted.

+
+ +

                                                                                                             +

+ +

The +Server sending a SUBACK packet MUST use one of the Subscribe Reason Codes for each Topic Filter received [MQTT-3.9.3-2].

+ +

 

+ +

Non-normative comment

+ +

There is always one Reason Code for +each Topic Filter in the corresponding SUBSCRIBE packet. If the Reason Code is +not specific to a Topic Filters (such as 0x91 (Packet Identifier in use)) it is +set for each Topic Filter.

+ +

 

+ +

3.10 UNSUBSCRIBE – Unsubscribe +request

+ +

An UNSUBSCRIBE packet is sent by the Client to the Server, +to unsubscribe from topics.

+ +

 

+ +

3.10.1 UNSUBSCRIBE Fixed +Header

+ +

Figure +3.28 – UNSUBSCRIBE packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (10)

+
+

Reserved

+
+

 

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Bits 3,2,1 and 0 of the +Fixed Header of the UNSUBSCRIBE packet are reserved and MUST be set to 0,0,1 +and 0 respectively. The Server MUST treat any other value as malformed and +close the Network Connection [MQTT-3.10.1-1].

+ +

 

+ +

Remaining Length field

+ +

This is the length of Variable Header (2 bytes) plus the +length of the Payload, encoded as a Variable Byte Integer.

+ +

 

+ +

3.10.2 UNSUBSCRIBE Variable +Header

+ +

The Variable Header of the UNSUBSCRIBE Packet contains the +following fields in the order: Packet Identifier, and Properties. Section 2.2.1 provides more information about Packet +Identifiers. The rules for encoding Properties are described in section 2.2.2.

+ +

 

+ +

3.10.2.1 UNSUBSCRIBE +Properties

+ +
3.10.2.1.1 Property Length
+ +

The length of Properties in the UNSUBSCRIBE packet Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +
3.10.2.1.2 User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by a UTF-8 String Pair.

+ +

 

+ +

The User Property is allowed to appear multiple times to +represent multiple name, value pairs. The same name is allowed to appear more +than once.

+ +

 

+ +

Non-normative comment

+ +

User Properties on the UNSUBSCRIBE +packet can be used to send subscription related properties from the Client to +the Server. The meaning of these properties is not defined by this +specification.

+ +

 

+ +

3.10.3 UNSUBSCRIBE Payload

+ +

The Payload for the UNSUBSCRIBE packet contains the list of +Topic Filters that the Client wishes to unsubscribe from. The Topic Filters in an UNSUBSCRIBE packet MUST be +UTF-8 Encoded Strings [MQTT-3.10.3-1] as +defined in section 1.5.4, packed +contiguously.

+ +

 

+ +

The Payload of an +UNSUBSCRIBE packet MUST contain at least one Topic Filter [MQTT-3.10.3-2]. An UNSUBSCRIBE packet with no Payload +is a Protocol Error. Refer to section 4.13 for +information about handling errors.

+ +

 

+ +

Non-normative example

+ +

Figure +3.30 shows the Payload for an UNSUBSCRIBE packet with two Topic Filters “a/b” +and “c/d”.

+ +

 

+ +

Figure 3.30 - Payload byte format non-normative example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Topic Filter

+
+

byte 1

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Length LSB (3)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 3

+
+

‘a’ (0x61)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 4

+
+

‘/’ (0x2F)

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

1

+
+

1

+
+

1

+
+

byte 5

+
+

‘b’ (0x62)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

Topic Filter

+
+

byte 6

+
+

Length MSB (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 7

+
+

Length LSB (3)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 8

+
+

‘c’ (0x63)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

byte 9

+
+

‘/’ (0x2F)

+
+

0

+
+

0

+
+

1

+
+

0

+
+

1

+
+

1

+
+

1

+
+

1

+
+

byte 10

+
+

‘d’ (0x64)

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+ +

 

+ +

3.10.4 UNSUBSCRIBE Actions

+ +

The Topic Filters (whether +they contain wildcards or not) supplied in an UNSUBSCRIBE packet MUST be +compared character-by-character with the current set of Topic Filters held by +the Server for the Client. If any filter matches exactly then its owning +Subscription MUST be deleted [MQTT-3.10.4-1], +otherwise no additional processing occurs.

+ +

 

+ +

When a Server receives +UNSUBSCRIBE :

+ + + +

 

+ +

The Server MUST respond to +an UNSUBSCRIBE request by sending an UNSUBACK packet [MQTT-3.10.4-4]. The +UNSUBACK packet MUST have the same Packet Identifier as the UNSUBSCRIBE packet. +Even where no Topic Subscriptions are deleted, the Server MUST respond with an +UNSUBACK [MQTT-3.10.4-5].

+ +

 

+ +

If a Server receives an +UNSUBSCRIBE packet that contains multiple Topic Filters, it MUST process that +packet as if it had received a sequence of multiple UNSUBSCRIBE packets, except +that it sends just one UNSUBACK response [MQTT-3.10.4-6].

+ +

 

+ +

If a Topic Filter represents a Shared Subscription, this +Session is detached from the Shared Subscription.  If this Session was the only +Session that the Shared Subscription was associated with, the Shared +Subscription is deleted. Refer to section +4.8.2 for a description of Shared Subscription handling.

+ +

 

+ +

3.11 UNSUBACK – Unsubscribe acknowledgement

+ +

The UNSUBACK packet is sent by the Server to the Client to +confirm receipt of an UNSUBSCRIBE packet.

+ +

 

+ +

3.11.1 UNSUBACK Fixed Header

+ +

Figure +3.31 – UNSUBACK packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (11)

+
+

Reserved

+
+

 

+
+

1

+
+

0

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable Header plus the length of +the Payload, encoded as a Variable Byte Integer.

+ +

 

+ +

3.11.2 UNSUBACK Variable +Header

+ +

The Variable Header of the UNSUBACK Packet the following +fields in the order: the Packet Identifier from the UNSUBSCRIBE Packet that is +being acknowledged, and Properties. The rules for encoding Properties are +described in section 2.2.2.

+ +

 

+ +

Figure +3.32 – UNSUBACK packet Variable Header

+ + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

Packet Identifier + MSB

+
+

byte 2

+
+

Packet Identifier + LSB

+
+ +

 

+ +

3.11.2.1 UNSUBACK Properties

+ +
3.11.2.1.1 Property Length
+ +

The length of the Properties in the UNSUBACK packet Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +
3.11.2.1.2 Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +associated with this response. This Reason String is a human readable string +designed for diagnostics and SHOULD NOT be parsed by the Client.

+ +

 

+ +

The Server uses this value to give additional information to +the Client. The Server MUST NOT send this +Property if it would increase the size of the UNSUBACK packet beyond the +Maximum Packet Size specified by the Client [MQTT-3.11.2-1]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.11.2.1.3 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property can be used to +provide additional diagnostic or other information. The Server MUST NOT send this property if it would increase the size of +the UNSUBACK packet beyond the Maximum Packet Size specified by the Client +[MQTT-3.11.2-2]. The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

3.11.3 +UNSUBACK Payload

+ +

The Payload contains a list of Reason Codes. Each Reason +Code corresponds to a Topic Filter in the UNSUBSCRIBE packet being +acknowledged. The order of Reason Codes in the +UNSUBACK packet MUST match the order of Topic Filters in the UNSUBSCRIBE packet +[MQTT-3.11.3-1].

+ +

 

+ +

The values for the one byte unsigned Unsubscribe Reason +Codes are shown below. The Server sending an +UNSUBACK packet MUST use one of the Unsubscribe Reason Code values for each +Topic Filter received [MQTT-3.11.3-2].

+ +

 

+ +

Table 3‑9 - Unsubscribe +Reason Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

The subscription is deleted.

+
+

17

+
+

0x11

+
+

No subscription existed

+
+

No matching Topic Filter is being used by the Client.

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

The unsubscribe could not be completed and the Server + either does not wish to reveal the reason or none of the other Reason Codes + apply.

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

The UNSUBSCRIBE is valid but the Server does not accept + it.

+
+

135

+
+

0x87

+
+

Not authorized

+
+

The Client is not authorized to unsubscribe.

+
+

143

+
+

0x8F

+
+

Topic Filter invalid

+
+

The Topic Filter is correctly formed but is not allowed + for this Client.

+
+

145

+
+

0x91

+
+

Packet Identifier in use

+
+

The specified Packet Identifier is already in use.

+
+ +

 

+ +

Non-normative comment

+ +

There is always one Reason Code for +each Topic Filter in the corresponding UNSUBSCRIBE packet. If the Reason Code +is not specific to a Topic Filters (such as 0x91 (Packet Identifier in use)) it +is set for each Topic Filter.

+ +

 

+ +

3.12 PINGREQ – PING request

+ +

The PINGREQ packet is sent from a Client to the Server. It +can be used to:

+ +

·         +Indicate to the Server that the Client is alive in the absence of +any other MQTT Control Packets being sent from the Client to the Server.

+ +

·         +Request that the Server responds to confirm that it is alive.

+ +

·         +Exercise the network to indicate that the Network Connection is +active.

+ +

 

+ +

This packet is used in Keep Alive +processing. Refer to section 3.1.2.10 for more +details.

+ +

 

+ +

3.12.1 PINGREQ Fixed Header

+ +

Figure +3.33 – PINGREQ packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (12)

+
+

Reserved

+
+

 

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length + (0)

+
+

 

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+ +

 

+ +

3.12.2 PINGREQ Variable Header

+ +

The PINGREQ packet has no Variable Header.

+ +

 

+ +

3.12.3 PINGREQ Payload

+ +

The PINGREQ packet has no Payload.

+ +

 

+ +

3.12.4 PINGREQ Actions

+ +

The Server MUST send a +PINGRESP packet in response to a PINGREQ packet [MQTT-3.12.4-1].

+ +

 

+ +

3.13 PINGRESP – PING response

+ +

A PINGRESP Packet is sent by the Server to the Client in +response to a PINGREQ packet. It indicates that the Server is alive.

+ +

 

+ +

This packet is used in Keep Alive +processing. Refer to section 3.1.2.10 for more +details.

+ +

 

+ +

3.13.1 PINGRESP Fixed Header

+ +

Figure +3.34 – PINGRESP packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (13)

+
+

Reserved

+
+

 

+
+

1

+
+

1

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length + (0)

+
+

 

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+ +

 

+ +

3.13.2 PINGRESP Variable Header

+ +

The PINGRESP packet has no Variable Header.

+ +

 

+ +

3.13.3 PINGRESP Payload

+ +

The PINGRESP packet has no Payload.

+ +

 

+ +

3.13.4 PINGRESP Actions

+ +

The Client takes no action on receiving this packet

+ +

 

+ +

3.14 DISCONNECT – Disconnect +notification

+ +

The DISCONNECT packet is the final MQTT Control Packet sent +from the Client or the Server. It indicates the reason why the Network +Connection is being closed. The Client or Server MAY send a DISCONNECT packet +before closing the Network Connection. If the Network Connection is closed without +the Client first sending a DISCONNECT packet with Reason Code 0x00 (Normal +disconnection) and the Connection has a Will Message, the Will Message is published. +Refer to section 3.1.2.5 for further details.

+ +

 

+ +

A Server MUST NOT send a DISCONNECT +until after it has sent a CONNACK with Reason Code of less than 0x80 [MQTT-3.14.0-1].

+ +

 

+ +

3.14.1 DISCONNECT Fixed Header

+ +

Figure +3.35 – DISCONNECT packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (14)

+
+

Reserved

+
+

 

+
+

1

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

The Client or Server MUST +validate that reserved bits are set to 0. If they are not zero it sends a +DISCONNECT packet with a Reason code of 0x81 (Malformed Packet) as described in +section 4.13 [MQTT-3.14.1-1].

+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +

3.14.2 DISCONNECT Variable Header

+ +

The Variable Header of the DISCONNECT Packet contains the +following fields in the order: Disconnect Reason Code, and Properties. The +rules for encoding Properties are described in section +2.2.2.

+ +

 

+ +

3.14.2.1 Disconnect Reason Code

+ +

Byte 1 in the Variable Header is the Disconnect Reason Code. +If the Remaining Length is less than 1 the value of 0x00 (Normal disconnection) +is used.

+ +

 

+ +

The values for the one byte unsigned Disconnect Reason Code +field are shown below.

+ +

 

+ +

Table 3‑10 – +Disconnect Reason Code values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Sent by

+
+

Description

+
+

0

+
+

0x00

+
+

Normal disconnection

+
+

Client or Server

+
+

Close the connection normally. Do not send the Will + Message.

+
+

4

+
+

0x04

+
+

Disconnect with Will Message

+
+

Client

+
+

The Client wishes to disconnect but requires that the + Server also publishes its Will Message.

+
+

128

+
+

0x80

+
+

Unspecified error

+
+

Client or Server

+
+

The Connection is closed but the sender either does not + wish to reveal the reason, or none of the other Reason Codes apply.

+
+

129

+
+

0x81

+
+

Malformed Packet

+
+

Client or Server

+
+

The received packet does not conform to this specification.

+
+

130

+
+

0x82

+
+

Protocol Error

+
+

Client or Server

+
+

An unexpected or out of order packet was received.

+
+

131

+
+

0x83

+
+

Implementation specific error

+
+

Client or Server

+
+

The packet received is valid but cannot be processed by + this implementation.

+
+

135

+
+

0x87

+
+

Not authorized

+
+

Server

+
+

The request is not authorized.

+
+

137

+
+

0x89

+
+

Server busy

+
+

Server

+
+

The Server is busy and cannot continue processing requests + from this Client.

+
+

139

+
+

0x8B

+
+

Server shutting down

+
+

Server

+
+

The Server is shutting down.

+
+

141

+
+

0x8D

+
+

Keep Alive timeout

+
+

Server

+
+

The Connection is closed because no packet has been + received for 1.5 times the Keepalive time.

+
+

142

+
+

0x8E

+
+

Session taken over

+
+

Server

+
+

Another Connection using the same ClientID has connected + causing this Connection to be closed.

+
+

143

+
+

0x8F

+
+

Topic Filter invalid

+
+

Server

+
+

The Topic Filter is correctly formed, but is not accepted + by this Sever.

+
+

144

+
+

0x90

+
+

Topic Name invalid

+
+

Client or Server

+
+

The Topic Name is correctly formed, but is not accepted by + this Client or Server.

+
+

147

+
+

0x93

+
+

Receive Maximum exceeded

+
+

Client or Server

+
+

The Client or Server has received more than Receive + Maximum publication for which it has not sent PUBACK or PUBCOMP.

+
+

148

+
+

0x94

+
+

Topic Alias invalid

+
+

Client or Server

+
+

The Client or Server has received a PUBLISH packet + containing a Topic Alias which is greater than the Maximum Topic Alias it + sent in the CONNECT or CONNACK packet.

+
+

149

+
+

0x95

+
+

Packet too large

+
+

Client or Server

+
+

The packet size is greater than Maximum Packet Size for + this Client or Server.

+
+

150

+
+

0x96

+
+

Message rate too high

+
+

Client or Server

+
+

The received data rate is too high.

+
+

151

+
+

0x97

+
+

Quota exceeded

+
+

Client or Server

+
+

An implementation or administrative imposed limit has been + exceeded.

+
+

152

+
+

0x98

+
+

Administrative action

+
+

Client or Server

+
+

The Connection is closed due to an administrative action.

+
+

153

+
+

0x99

+
+

Payload format invalid

+
+

Client or Server

+
+

The payload format does not match the one specified by the + Payload Format Indicator.

+
+

154

+
+

0x9A

+
+

Retain not supported

+
+

Server

+
+

The Server has does not support retained messages.

+
+

155

+
+

0x9B

+
+

QoS not supported

+
+

Server

+
+

The Client specified a QoS greater than the QoS specified + in a Maximum QoS in the CONNACK.

+
+

156

+
+

0x9C

+
+

Use another server

+
+

Server

+
+

The Client should temporarily change its Server.

+
+

157

+
+

0x9D

+
+

Server moved

+
+

Server

+
+

The Server is moved and the Client should permanently + change its server location.

+
+

158

+
+

0x9E

+
+

Shared Subscriptions not supported

+
+

Server

+
+

The Server does not support Shared Subscriptions.

+
+

159

+
+

0x9F

+
+

Connection rate exceeded

+
+

Server

+
+

This connection is closed because the connection rate is + too high.

+
+

160

+
+

0xA0

+
+

Maximum connect time

+
+

Server

+
+

The maximum connection time authorized for this connection + has been exceeded.

+
+

161

+
+

0xA1

+
+

Subscription Identifiers not supported

+
+

Server

+
+

The Server does not support Subscription Identifiers; the + subscription is not accepted.

+
+

162

+
+

0xA2

+
+

Wildcard Subscriptions not supported

+
+

Server

+
+

The Server does not support Wildcard Subscriptions; the + subscription is not accepted.

+
+ +

 

+ +

The Client or Server sending +the DISCONNECT packet MUST use one of the DISCONNECT Reason Code values [MQTT-3.14.2-1]. The +Reason Code and Property Length can be omitted if the Reason Code is 0x00 +(Normal disconnecton) and there are no Properties. In this case the DISCONNECT +has a Remaining Length of 0.

+ +

 

+ +

Non-normative comment

+ +

The DISCONNECT packet is used to +indicate the reason for a disconnect for cases where there is no acknowledge packet +(such as a QoS 0 publish) or when the Client or Server is unable to continue +processing the Connection.

+ +

 

+ +

Non-normative comment

+ +

The information can be used by the +Client to decide whether to retry the connection, and how long it should wait +before retrying the connection.

+ +

 

+ +

3.14.2.2 DISCONNECT Properties

+ +
3.14.2.2.1 +Property Length
+ +

The length of Properties in the DISCONNECT packet Variable +Header encoded as a Variable Byte Integer. If the Remaining Length is less than +2, a value of 0 is used.

+ +

 

+ +
3.14.2.2.2 Session Expiry Interval
+ +

17 (0x11) Byte, Identifier of the Session Expiry +Interval.

+ +

Followed by the Four Byte Integer representing the Session +Expiry Interval in seconds. It is a Protocol Error to include the Session +Expiry Interval more than once.

+ +

 

+ +

If the Session Expiry Interval is absent, the Session Expiry +Interval in the CONNECT packet is used.

+ +

 

+ +

The Session Expiry Interval +MUST NOT be sent on a DISCONNECT by the Server [MQTT-3.14.2-2].

+ +

 

+ +

If the Session Expiry Interval in the CONNECT packet was +zero, then it is a Protocol Error to set a non-zero Session Expiry Interval in +the DISCONNECT packet sent by the Client. If such a non-zero Session Expiry +Interval is received by the Server, it does not treat it as a valid DISCONNECT +packet. The Server uses DISCONNECT with Reason Code 0x82 (Protocol Error) as +described in section 4.13.

+ +

 

+ +
3.14.2.2.3 +Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +for the disconnect. This Reason String is human readable, designed for +diagnostics and SHOULD NOT be parsed by the receiver.

+ +

 

+ +

The sender MUST NOT send +this Property if it would increase the size of the DISCONNECT packet beyond the +Maximum Packet Size specified by the receiver [MQTT-3.14.2-3]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.14.2.2.4 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property may be used to +provide additional diagnostic or other information. The sender MUST NOT send this property if it would increase the size of +the DISCONNECT packet beyond the Maximum Packet Size specified by the receiver +[MQTT-3.14.2-4]. The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +
3.14.2.2.5 +Server Reference
+ +

28 (0x1C) Byte, Identifier of the Server Reference.

+ +

Followed by a UTF-8 Encoded String which can be used by the +Client to identify another Server to use. It is a Protocol Error to include the +Server Reference more than once.

+ +

 

+ +

The Server sends DISCONNECT including a Server Reference and +Reason Code 0x9C (Use another server) or 0x9D (Server moved) as described in section 4.13.

+ +

 

+ +

Refer to section 4.11 +Server Redirection for information about how Server Reference is used.

+ +

 

+ +

Figure 3‑24 +DISCONNECT packet Variable Header non-normative example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

Description

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

Disconnect Reason Code

+
+

byte 1

+
+

 

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

Properties

+
+

byte 2

+
+

Length (5)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

1

+
+

1

+
+

1

+
+

byte 3

+
+

Session Expiry Interval identifier (17)

+
+

0

+
+

0

+
+

0

+
+

1

+
+

0

+
+

0

+
+

0

+
+

1

+
+

byte 4

+
+

Session Expiry Interval (0)

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 5

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 6

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 7

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+

0

+
+ +

 

+ +

3.14.3 DISCONNECT Payload

+ +

The DISCONNECT packet has no Payload.

+ +

 

+ +

3.14.4 +DISCONNECT Actions

+ +

After sending a DISCONNECT +packet the sender:

+ + + +

 

+ +

On receipt of DISCONNECT +with a Reason Code of 0x00 (Success) the Server:

+ + + +

 

+ +

On receipt of DISCONNECT, the receiver:

+ + + +

 

+ +

3.15 +AUTH – Authentication exchange

+ +

An AUTH packet is sent from Client to Server or Server to +Client as part of an extended authentication exchange, such as challenge / response +authentication. It is a Protocol Error for the Client or Server to send an AUTH +packet if the CONNECT packet did not contain the same Authentication Method.

+ +

 

+ +

3.15.1 AUTH Fixed Header

+ +

Figure 3.35 – AUTH packet Fixed Header

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bit

+
+

7

+
+

6

+
+

5

+
+

4

+
+

3

+
+

2

+
+

1

+
+

0

+
+

byte 1

+
+

MQTT Control Packet + type (15)

+
+

Reserved

+
+

 

+
+

1

+
+

1

+
+

1

+
+

1

+
+

0

+
+

0

+
+

0

+
+

0

+
+

byte 2

+
+

Remaining Length

+
+ +

 

+ +

Bits 3,2,1 and 0 of the +Fixed Header of the AUTH packet are reserved and MUST all be set to 0. The +Client or Server MUST treat any other value as malformed and close the Network +Connection [MQTT-3.15.1-1].

+ +

 

+ +

Remaining Length field

+ +

This is the length of the Variable +Header encoded as a Variable Byte Integer.

+ +

 

+ +

3.15.2 AUTH Variable Header

+ +

The Variable Header of the AUTH Packet contains the +following fields in the order: Authenticate Reason Code, and Properties. The +rules for encoding Properties are described in section +2.2.2.

+ +

 

+ +

3.15.2.1 Authenticate Reason Code

+ +

Byte 0 in the Variable Header is the Authenticate Reason +Code. The values for the one byte unsigned Authenticate Reason Code field are shown +below. The sender of the AUTH Packet MUST use +one of the Authenticate Reason Codes [MQTT-3.15.2-1].

+ +

 

+ +

Table 3‑11 Authenticate Reason Codes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Value

+
+

Hex

+
+

Reason Code name

+
+

Sent by

+
+

Description

+
+

0

+
+

0x00

+
+

Success

+
+

Server

+
+

Authentication is successful

+
+

24

+
+

0x18

+
+

Continue authentication

+
+

Client or Server

+
+

Continue the authentication with another step

+
+

25

+
+

0x19

+
+

Re-authenticate

+
+

Client

+
+

Initiate a re-authentication

+
+ +

The Reason Code and Property Length can be omitted if the +Reason Code is 0x00 (Success) and there are no Properties. In this case the +AUTH has a Remaining Length of 0.

+ +

 

+ +

3.15.2.2 AUTH Properties

+ +
3.15.2.2.1 Property Length
+ +

The length of Properties in the AUTH packet Variable Header +encoded as a Variable Byte Integer.

+ +

 

+ +
3.15.2.2.2 Authentication Method
+ +

21 (0x15) Byte, Identifier of the Authentication +Method.

+ +

Followed by a UTF-8 Encoded String containing the name of +the authentication method. It is a Protocol Error to omit the Authentication +Method or to include it more than once. Refer to section 4.12 for more information about extended +authentication.

+ +

 

+ +
3.15.2.2.3 Authentication Data
+ +

22 (0x16) Byte, Identifier of the Authentication +Data.

+ +

Followed by Binary Data containing authentication data. It +is a Protocol Error to include Authentication Data more than once. The contents +of this data are defined by the authentication method. Refer to section 4.12 for more information about +extended authentication.

+ +

 

+ +
3.15.2.2.4 Reason String
+ +

31 (0x1F) Byte, Identifier of the Reason String.

+ +

Followed by the UTF-8 Encoded String representing the reason +for the disconnect. This Reason String is human readable, designed for +diagnostics and SHOULD NOT be parsed by the receiver.

+ +

 

+ +

The sender MUST NOT send +this property if it would increase the size of the AUTH packet beyond the +Maximum Packet Size specified by the receiver [MQTT-3.15.2-2]. +It is a Protocol Error to include the Reason String more than once.

+ +

 

+ +
3.15.2.2.5 +User Property
+ +

38 (0x26) Byte, Identifier of the User Property.

+ +

Followed by UTF-8 String Pair. This property may be used to +provide additional diagnostic or other information. The sender MUST NOT send this property if it would increase the size of +the AUTH packet beyond the Maximum Packet Size specified by the receiver +[MQTT-3.15.2-3]. The User Property is allowed to +appear multiple times to represent multiple name, value pairs. The same name is +allowed to appear more than once.

+ +

 

+ +

3.15.3 AUTH Payload

+ +

The AUTH packet has no Payload.

+ +

 

+ +

3.15.4 +AUTH Actions

+ +

Refer to section 4.12 +for more information about extended authentication.

+ +
+ +

4      +Operational behavior

+ +
+ +

4.1 Session State

+ +

In order to implement QoS 1 and QoS 2 protocol flows the +Client and Server need to associate state with the Client Identifier, this is +referred to as the Session State. The Server also stores the subscriptions as +part of the Session State.

+ +

 

+ +

The session can continue across a sequence of Network +Connections. It lasts as long as the latest Network Connection plus the Session +Expiry Interval.

+ +

 

+ +

The Session State in the Client consists of:

+ +

·         +QoS 1 and QoS 2 messages which have been sent to the Server, but +have not been completely acknowledged.

+ +

·         +QoS 2 messages which have been received from the Server, but have +not been completely acknowledged.

+ +

 

+ +

The Session State in the Server consists of:

+ +

·         +The existence of a Session, even if the rest of the Session State +is empty.

+ +

·         +The Clients subscriptions, including any Subscription +Identifiers.

+ +

·         +QoS 1 and QoS 2 messages which have been sent to the Client, but +have not been completely acknowledged.

+ +

·         +QoS 1 and QoS 2 messages pending transmission to the Client and +OPTIONALLY QoS 0 messages pending transmission to the Client.

+ +

·         +QoS 2 messages which have been received from the Client, but have +not been completely acknowledged.The Will Message and the Will Delay Interval

+ +

·         +If the Session is currently not connected, the time at which the Session +will end and Session State will be discarded.

+ +

 

+ +

Retained messages do not form part of the Session State in +the Server, they are not deleted as a result of a Session ending.

+ +

 

+ +

4.1.1 Storing Session State

+ +

The Client and Server MUST NOT +discard the Session State while the Network Connection is open [MQTT-4.1.0-1]. The +Server MUST discard the Session State when the Network Connection is closed and +the Session Expiry Interval has passed [MQTT-4.1.0-2].

+ +

 

+ +

Non-normative +comment

+ +

The storage capabilities of Client +and Server implementations will of course have limits in terms of capacity and +may be subject to administrative policies. Stored Session State can be +discarded as a result of an administrator action, including an automated +response to defined conditions. This has the effect of terminating the Session. +These actions might be prompted by resource constraints or for other +operational reasons. It is possible that hardware or software failures may +result in loss or corruption of Session State stored by the Client or Server. It +is prudent to evaluate the storage capabilities of the Client and Server to +ensure that they are sufficient.

+ +

 

+ +

4.1.2 Session State non-normative +examples

+ +

For example, an electricity meter reading solution might use +QoS 1 messages to protect the readings against loss over the network. The +solution developer might have determined that the power supply is sufficiently +reliable that, in this case, the data in the Client and Server can be stored in +volatile memory without too much risk of its loss.

+ +

 

+ +

Conversely a parking meter payment application provider +might decide that the payment messages should never be lost due to a network or +Client failure. Thus, they require that all data be written to non-volatile +memory before it is transmitted across the network.

+ +

 

+ +

4.2 Network Connections

+ +

The MQTT protocol requires an underlying transport that +provides an ordered, lossless, stream of bytes from the Client to Server and +Server to Client. This specification does not require the support of any +specific transport protocol. A Client or Server MAY support any of the +transport protocols listed here, or any other transport protocol that meets the +requirements of this section.

+ +

 

+ +

A Client or Server MUST +support the use of one or more underlying transport protocols that provide an +ordered, lossless, stream of bytes from the Client to Server and Server to +Client [MQTT-4.2-1].

+ +

 

+ +

Non-normative +comment

+ +

TCP/IP as defined in [RFC0793] can be used for MQTT v5.0. The following transport +protocols are also suitable:

+ +

·         +TLS [RFC5246]

+ +

·         +WebSocket [RFC6455]

+ +

 

+ +

Non-normative comment

+ +

TCP ports 8883 and 1883 are +registered with IANA for MQTT TLS and non-TLS communication respectively.

+ +

 

+ +

Non-normative comment

+ +

Connectionless network transports +such as User Datagram Protocol (UDP) are not +suitable on their own because they might lose or reorder data.

+ +

 

+ +

4.3 Quality of Service levels and protocol flows

+ +

MQTT delivers Application Messages according to the Quality +of Service (QoS) levels defined in the following sections. The delivery +protocol is symmetric, in the description below the Client and Server can each +take the role of either sender or receiver. The delivery protocol is concerned +solely with the delivery of an application message from a single sender to a +single receiver. When the Server is delivering an Application Message to more +than one Client, each Client is treated independently. The QoS level used to +deliver an Application Message outbound to the Client could differ from that of +the inbound Application Message.

+ +

 

+ +

4.3.1 QoS 0: At most once +delivery

+ +

The message is delivered according to the capabilities of +the underlying network. No response is sent by the receiver and no retry is +performed by the sender. The message arrives at the receiver either once or not +at all.

+ +

 

+ +

In +the QoS 0 delivery protocol, the sender

+ +

·         +MUST send a PUBLISH packet with +QoS 0 and DUP flag set to 0 [MQTT-4.3.1-1].

+ +

 

+ +

In the QoS 0 delivery protocol, the receiver

+ +

·         +Accepts ownership of the message when it receives the PUBLISH +packet.

+ +

 

+ +

Figure 4.1 – QoS 0 protocol flow diagram, non-normative +example

+ + + + + + + + + + + + + + + + + + + + + + +
+

Sender Action

+
+

Control Packet

+
+

Receiver Action

+
+

PUBLISH QoS 0, + DUP=0

+

 

+
+

 

+
+

 

+
+

 

+
+

---------->

+
+

 

+
+

 

+
+

 

+
+

Deliver Application + Message to appropriate onward recipient(s)

+
+ +

 

+ +

4.3.2 QoS 1: At least once +delivery

+ +

This Quality of Service level ensures +that the message arrives at the receiver at least once. A QoS 1 PUBLISH packet +has a Packet Identifier in its Variable Header and is acknowledged by a PUBACK packet. +Section 2.2.1 provides more information about Packet +Identifiers.

+ +

 

+ +

In +the QoS 1 delivery protocol, the sender

+ +

·         +MUST assign an unused Packet +Identifier each time it has a new Application Message to publish [MQTT-4.3.2-1].

+ +

·         +MUST send a PUBLISH packet +containing this Packet Identifier with QoS 1 and DUP flag set to 0 [MQTT-4.3.2-2].

+ +

·         +MUST treat the PUBLISH packet as +“unacknowledged” until it has received the corresponding PUBACK packet from the +receiver. Refer to section 4.4 +for a discussion of unacknowledged messages [MQTT-4.3.2-3].

+ +

 

+ +

The Packet Identifier becomes +available for reuse once the sender has received the PUBACK packet.

+ +

 

+ +

Note that a sender is permitted to +send further PUBLISH packets with different Packet Identifiers while it is +waiting to receive acknowledgements.

+ +

 

+ +

In +the QoS 1 delivery protocol, the receiver

+ + + +

 

+ +

Figure 4.2 – QoS 1 protocol flow diagram, non-normative +example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Sender Action

+
+

MQTT Control + Packet

+
+

Receiver action

+
+

Store message

+
+

 

+
+

 

+
+

Send PUBLISH QoS 1, DUP=0, <Packet Identifier>

+
+

---------->

+
+

 

+
+

 

+
+

 

+
+

Initiate onward delivery of the Application Message1

+
+

 

+
+

<----------

+
+

Send PUBACK + <Packet Identifier>

+
+

Discard message

+
+

 

+
+

 

+
+ +

 

+ +

1 The receiver does not +need to complete delivery of the Application Message before sending the PUBACK. +When its original sender receives the PUBACK packet, ownership of the Application +Message is transferred to the receiver.

+ +

 

+ +

4.3.3 +QoS 2: Exactly once delivery

+ +

This is the highest Quality of Service level, for use when +neither loss nor duplication of messages are acceptable. There is an increased +overhead associated with QoS 2.

+ +

 

+ +

A QoS 2 message has a Packet Identifier in its Variable +Header. Section 2.2.1 provides more information +about Packet Identifiers. The receiver of a QoS 2 PUBLISH packet acknowledges +receipt with a two-step acknowledgement process.

+ +

 

+ +

In +the QoS 2 delivery protocol, the sender:

+ + + +

 

+ +

The Packet Identifier becomes +available for reuse once the sender has received the PUBCOMP packet or a PUBREC +with a Reason Code of 0x80 or greater.

+ +

 

+ +

Note that a sender is permitted +to send further PUBLISH packets with different Packet Identifiers while it is +waiting to receive acknowledgements, subject to flow control as described in section 4.9.

+ +

 

+ +

In +the QoS 2 delivery protocol, the receiver:

+ + + +

 

+ +

4.4 Message delivery retry

+ +

When a Client reconnects +with Clean Start set to 0 and a session is present, both the Client and Server +MUST resend any unacknowledged PUBLISH packets (where QoS > 0) and PUBREL +packets using their original Packet Identifiers. This is the only circumstance where a Client or Server +is REQUIRED to resend messages. Clients and Servers MUST NOT resend messages at +any other time [MQTT-4.4.0-1].

+ +

 

+ +

If PUBACK or PUBREC is +received containing a Reason Code of 0x80 or greater the corresponding PUBLISH +packet is treated as acknowledged, and MUST NOT be retransmitted [MQTT-4.4.0-2].

+ +

 

+ +

Figure 4.3 – QoS 2 protocol flow +diagram, non-normative example

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Sender Action

+
+

MQTT Control + Packet

+
+

Receiver Action

+
+

Store message

+
+

 

+
+

 

+
+

PUBLISH QoS 2, DUP=0
+  <Packet Identifier>

+
+

 

+
+

 

+
+

 

+
+

---------->

+
+

 

+
+

 

+
+

 

+
+

Store <Packet Identifier> then Initiate onward + delivery of the Application Message1

+
+

 

+
+

 

+
+

PUBREC <Packet Identifier><Reason Code>

+
+

 

+
+

<----------

+
+

 

+
+

Discard message, Store PUBREC received <Packet Identifier>

+
+

 

+
+

 

+
+

PUBREL <Packet Identifier>

+
+

 

+
+

 

+
+

 

+
+

---------->

+
+

 

+
+

 

+
+

 

+
+

Discard <Packet Identifier>

+
+

 

+
+

 

+
+

Send PUBCOMP <Packet Identifier>

+
+

 

+
+

<----------

+
+

 

+
+

Discard stored state

+
+

 

+
+

 

+
+ +

 

+ +

1 The receiver does not +need to complete delivery of the Application Message before sending the PUBREC +or PUBCOMP. When its original sender receives the PUBREC packet, ownership of +the Application Message is transferred to the receiver. However, the receiver +needs to perform all checks for conditions which might result in a forwarding +failure (e.g. quota exceeded, authorization, etc.) before accepting ownership. +The receiver indicates success or failure using the appropriate Reason Code in +the PUBREC.

+ +

 

+ +

4.5 Message receipt

+ +

When a Server takes +ownership of an incoming Application Message it MUST add it to the Session +State for those Clients that have matching Subscriptions [MQTT-4.5.0-1]. Matching rules are defined in section 4.7.

+ +

 

+ +

Under normal circumstances Clients receive messages in +response to Subscriptions they have created. A Client could also receive +messages that do not match any of its explicit Subscriptions. This can happen +if the Server automatically assigned a subscription to the Client. A Client +could also receive messages while an UNSUBSCRIBE operation is in progress. The Client MUST acknowledge any Publish packet it +receives according to the applicable QoS rules regardless of whether it elects +to process the Application Message that it contains [MQTT-4.5.0-2].

+ +

 

+ +

4.6 Message ordering

+ +

The following these rules apply to the Client when +implementing the protocol flows defined in section +4.3.

+ + + +

 

+ +

An Ordered Topic is a Topic where the Client can be certain +that the Application Messages in that Topic from the same Client and at the +same QoS are received are in the order they were published. When a Server processes a message that has been +published to an Ordered Topic, it MUST send PUBLISH packets to consumers (for +the same Topic and QoS) in the order that they were received from any given +Client [MQTT-4.6.0-5]. This is addition +to the rules listed above.

+ +

 

+ +

By default, a Server MUST treat +every Topic as an Ordered Topic when it is forwarding messages on Non‑shared +Subscriptions. [MQTT-4.6.0-6]. A Server MAY +provide an administrative or other mechanism to allow one or more Topics to not +be treated as an Ordered Topic.

+ +

 

+ +

Non-normative +comment

+ +

The rules listed above ensure that +when a stream of messages is published and subscribed to an Ordered Topic with +QoS 1, the final copy of each message received by the subscribers will be in +the order that they were published. If the message is re-sent the duplicate +message can be received after one of the earlier messages is received. For +example, a publisher might send messages in the order 1,2,3,4 but the +subscriber might receive them in the order 1,2,3,2,3,4 if there is a network +disconnection after message 3 has been sent.

+ +

 

+ +

If both +Client and Server set Receive Maximum to 1, they make sure that no more than +one message is “in-flight” at any one time. In this case no QoS 1 message will +be received after any later one even on re-connection. For example a subscriber +might receive them in the order 1,2,3,3,4 but not 1,2,3,2,3,4. Refer to section 4.9 Flow Control for details of how the +Receive Maximum is used.

+ +

 

+ +

4.7 Topic Names and Topic Filters

+ +

4.7.1 Topic wildcards

+ +

The topic level separator is used to introduce structure +into the Topic Name. If present, it divides the Topic Name into multiple “topic +levels”.

+ +

A subscription’s Topic Filter can contain special wildcard +characters, which allow a Client to subscribe to multiple topics at once.

+ +

The wildcard characters can +be used in Topic Filters, but MUST NOT be used within a Topic Name [MQTT-4.7.0-1].

+ +

 

+ +

4.7.1.1 Topic level separator

+ +

The forward slash (‘/’ U+002F) is used to separate each +level within a topic tree and provide a hierarchical structure to the Topic +Names. The use of the topic level separator is significant when either of the +two wildcard characters is encountered in Topic Filters specified by +subscribing Clients. Topic level separators can appear anywhere in a Topic +Filter or Topic Name. Adjacent Topic level separators indicate a zero-length +topic level.

+ +

 

+ +

4.7.1.2 Multi-level wildcard

+ +

The number sign (‘#’ U+0023) is a wildcard character that +matches any number of levels within a topic. The multi-level wildcard +represents the parent and any number of child levels. The multi-level wildcard character MUST be specified either on its own +or following a topic level separator. In either case it MUST be the last +character specified in the Topic Filter [MQTT-4.7.1-1].

+ +

 

+ +

Non-normative +comment

+ +

For example, if a Client subscribes +to “sport/tennis/player1/#”, it would receive messages published using these Topic +Names:

+ +

·         +“sport/tennis/player1”

+ +

·         +“sport/tennis/player1/ranking

+ +

·         +“sport/tennis/player1/score/wimbledon”

+ +

 

+ +

Non-normative +comment

+ +

·         +“sport/#” also matches the singular “sport”, since # includes the +parent level.

+ +

·         +“#” is valid and will receive every Application Message

+ +

·         +“sport/tennis/#” is valid

+ +

·         +“sport/tennis#” is not valid

+ +

·         +“sport/tennis/#/ranking” is not valid

+ +

 

+ +

4.7.1.3 Single-level wildcard

+ +

The plus sign (‘+’ U+002B) is a wildcard character that +matches only one topic level.

+ +

 

+ +

The single-level wildcard +can be used at any level in the Topic Filter, including first and last levels. +Where it is used, it MUST occupy an entire level of the filter [MQTT-4.7.1-2]. It can be used at more than one level +in the Topic Filter and can be used in conjunction with the multi-level +wildcard.

+ +

 

+ +

Non-normative +comment

+ +

For example, “sport/tennis/+” +matches “sport/tennis/player1” and “sport/tennis/player2”, but not +“sport/tennis/player1/ranking”. Also, because the single-level wildcard matches +only a single level, “sport/+” does not match “sport” but it does match +“sport/”.

+ +

·         + “+” is valid

+ +

·         +“+/tennis/#” is valid

+ +

·         +“sport+” is not valid

+ +

·         +“sport/+/player1” is valid

+ +

·         +“/finance” matches “+/+” and “/+”, but not “+”

+ +

 

+ +

4.7.2  Topics beginning with $

+ +

The Server MUST NOT match +Topic Filters starting with a wildcard character (# or +) with Topic Names +beginning with a $ character [MQTT-4.7.2-1]. +The Server SHOULD prevent Clients from using such Topic Names to exchange +messages with other Clients. Server implementations MAY use Topic Names that +start with a leading $ character for other purposes.

+ +

 

+ +

Non-normative +comment

+ +

·         +$SYS/ has been widely adopted as a prefix to topics that contain +Server-specific information or control APIs

+ +

·         +Applications cannot use a topic with a leading $ character for +their own purposes

+ +

 

+ +

Non-normative +comment

+ +

·         +A subscription to “#” will not receive any messages published to +a topic beginning with a $

+ +

·         +A subscription to “+/monitor/Clients” will not receive any +messages published to “$SYS/monitor/Clients”

+ +

·         +A subscription to “$SYS/#” will receive messages published to +topics beginning with “$SYS/”

+ +

·         +A subscription to “$SYS/monitor/+” will receive messages +published to “$SYS/monitor/Clients”

+ +

·         +For a Client to receive messages from topics that begin with +$SYS/ and from topics that don’t begin with a $, it has to subscribe to both “#” +and “$SYS/#”

+ +

 

+ +

4.7.3 Topic semantic and usage

+ +

The following rules apply to Topic Names and Topic Filters:

+ +

·         +All Topic Names and Topic Filters +MUST be at least one character long [MQTT-4.7.3-1]

+ +

·         +Topic Names and Topic Filters are case sensitive

+ +

·         +Topic Names and Topic Filters can include the space character

+ +

·         +A leading or trailing ‘/’ creates a distinct Topic Name or Topic +Filter

+ +

·         +A Topic Name or Topic Filter consisting only of the ‘/’ character +is valid

+ +

·         +Topic Names and Topic Filters +MUST NOT include the null character (Unicode U+0000) [Unicode] [MQTT-4.7.3-2]

+ +

·         +Topic Names and Topic Filters are +UTF-8 Encoded Strings; they MUST NOT encode to more than 65,535 bytes [MQTT-4.7.3-3]. Refer to section 1.5.4.

+ +

 

+ +

There is no limit to the number of levels in a Topic Name or +Topic Filter, other than that imposed by the overall length of a UTF-8 Encoded +String.

+ +

 

+ +

When it performs +subscription matching the Server MUST NOT perform any normalization of Topic +Names or Topic Filters, or any modification or substitution of unrecognized +characters [MQTT-4.7.3-4]. Each +non-wildcarded level in the Topic Filter has to match the corresponding level +in the Topic Name character for character for the match to succeed.

+ +

 

+ +

Non-normative +comment

+ +

The UTF-8 encoding rules mean that +the comparison of Topic Filter and Topic Name could be performed either by +comparing the encoded UTF-8 bytes, or by comparing decoded Unicode characters

+ +

 

+ +

Non-normative +comment

+ +

·         +“ACCOUNTS” and “Accounts” are two different Topic Names

+ +

·         +“Accounts payable” is a valid Topic Name

+ +

·         +“/finance” is different from “finance”

+ +

 

+ +

An Application Message is sent to each Client Subscription +whose Topic Filter matches the Topic Name attached to an Application Message. +The topic resource MAY be either predefined in the Server by an administrator +or it MAY be dynamically created by the Server when it receives the first +subscription or an Application Message with that Topic Name. The Server MAY +also use a security component to authorize particular actions on the topic +resource for a given Client.

+ +

 

+ +

4.8 Subscriptions

+ +

MQTT provides two kinds of Subscription, Shared and Non‑shared.

+ +

 

+ +

Non-normative comment

+ +

In earlier versions of MQTT all +Subscriptions are Non‑shared.

+ +

 

+ +

4.8.1 +Non‑shared Subscriptions

+ +

A Non‑shared Subscription is associated only with the +MQTT Session that created it. Each Subscription includes a Topic Filter, +indicating the topic(s) for which messages are to be delivered on that Session, +and Subscription Options. The Server is responsible for collecting messages +that match the filter and transmitting them on the Session's MQTT connection if +and when that connection is active.

+ +

 

+ +

A Session cannot have more than one Non‑shared +Subscription with the same Topic Filter, so the Topic Filter can be used as a key +to identify the subscription within that Session.

+ +

 

+ +

If there are multiple Clients, each with its own Non‑shared +Subscription to the same Topic, each Client gets its own copy of the +Application Messages that are published on that Topic. This means that the Non‑shared +Subscriptions cannot be used to load-balance Application Messages across +multiple consuming Clients as in such cases every message is delivered to every +subscribing Client.

+ +

 

+ +

4.8.2 Shared Subscriptions

+ +

A Shared Subscription can be associated with multiple +subscribing MQTT Sessions. Like a Non‑shared Subscription, it has a Topic +Filter and Subscription Options; however, a publication that matches its Topic +Filter is only sent to one of its subscribing Sessions. Shared Subscriptions +are useful where several consuming Clients share the processing of the +publications in parallel.

+ +

 

+ +

A Shared Subscription is identified using a special style of +Topic Filter. The format of this filter is:

+ +

 

+ +

$share/{ShareName}/{filter}

+ +

·         + $share is a literal string that marks the Topic Filter as being +a Shared Subscription Topic Filter.

+ +

·         + {ShareName} is a character string that does not include +"/", "+" or "#"

+ +

·         + {filter} The remainder of the string has the same syntax and +semantics as a Topic Filter in a non-shared subscription. Refer to section 4.7.

+ +

·         + 

+ +

A Shared Subscription's +Topic Filter MUST start with $share/ and MUST contain a ShareName that is at +least one character long [MQTT-4.8.2-1]. The ShareName MUST NOT contain the characters +"/", "+" or "#", but MUST be followed by a +"/" character. This "/" character MUST be followed by a +Topic Filter [MQTT-4.8.2-2] as described +in section 4.7.

+ +

 

+ +

Non-normative +comment

+ +

Shared Subscriptions are defined at +the scope of the MQTT Server, rather than of a Session. A ShareName is included +in the Shared Subscription's Topic Filter so that there can be more than one +Shared Subscription on a Server that has the same {filter} component. Typically, +applications use the ShareName to represent the group of subscribing Sessions +that are sharing the subscription.

+ +

 

+ +

Examples:

+ +

·         +Shared subscriptions "$share/consumer1/sport/tennis/+" +and "$share/consumer2/sport/tennis/+" are distinct shared +subscriptions and so can be associated with different groups of Sessions. Both +of them match the same topics as a non-shared subscription to sport/tennis/+ .

+ +

 

+ +

If a message were +to be published that matches sport/tennis/+ then a copy would be sent to +exactly one of the Sessions subscribed to $share/consumer1/sport/tennis/+ , a +separate copy of the message would be sent to exactly one of the Sessions +subscribed to $share/consumer2/sport/tennis/+ and further copies would be sent +to any Clients with non-shared subscriptions to sport/tennis/+

+ +

 

+ +

·         +Shared subscription "$share/consumer1//finance" matches +the same topics as a non-shared subscription to /finance.
+
+Note that "$share/consumer1//finance" and "$share/consumer1/sport/tennis/+" +are distinct shared subscriptions, even though they have the same ShareName. +While they might be related in some way, no specific relationship between them +is implied by them having the same ShareName.

+ +

 

+ +

A Shared Subscription is created by using a Shared +Subscription Topic Filter in a SUBSCRIBE request. So long as only one Session +subscribes to a particular Shared Subscription, the shared subscription behaves +like a non-shared subscription, except that:

+ +

 

+ +

·         +The $share and {ShareName} portions of the Topic Filter are not +taken into account when matching against publications.

+ +

 

+ +

·         +No Retained Messages are sent to the Session when it first +subscribes. It will be sent other matching messages as they are published.

+ +

 

+ +

Once a Shared Subscription exists, it is possible for other +Sessions to subscribe with the same Shared Subscription Topic Filter. The new Session +is associated with the Shared Subscription as an additional subscriber. +Retained messages are not sent to this new subscriber. Each subsequent +Application Message that matches the Shared Subscription is now sent to one and +only one of the Sessions that are subscribed to the Shared Subscription.

+ +

 

+ +

A Session can explicitly detach itself from a Shared +Subscription by sending an UNSUBSCRIBE Packet that contains the full Shared +Subscription Topic Filter. Sessions are also detached from the Shared Subscription +when they terminate.

+ +

 

+ +

A Shared Subscription lasts for as long as it is associated +with at least one Session (i.e. a Session that has issued a successful +SUBSCRIBE request to its Topic Filter and that has not completed a +corresponding UNSUBSCRIBE). A Shared Subscription survives when the Session +that originally created it unsubscribes, unless there are no other Sessions +left when this happens. A Shared Subscription ends, and any undelivered +messages associated with it are deleted, when there are no longer any Sessions +subscribed to it.

+ +

 

+ +

Notes on Shared Subscriptions

+ +

·         +If there's more than one Session subscribed to the Shared +Subscription, the Server implementation is free to choose, on a message by +message basis, which Session to use and what criteria it uses to make this +selection.
+
+

+ +

·         +Different subscribing Clients are permitted to ask for different +Requested QoS levels in their SUBSCRIBE packets. The Server decides which +Maximum QoS to grant to each Client, and it is permitted to grant different +Maximum QoS levels to different subscribers. When sending an Application +Message to a Client, the Server MUST respect +the granted QoS for the Client's subscription [MQTT-4.8.2-3], +in the same that it does when sending a message to a ‑Subscriber.
+
+

+ +

·         +If the Server is in the process of sending a QoS 2 message to its +chosen subscribing Client and the connection to the Client breaks before +delivery is complete, the Server MUST complete +the delivery of the message to that Client when it reconnects [MQTT-4.8.2-4] as described in section 4.3.3. If +the Client's Session terminates before the Client reconnects, the Server MUST +NOT send the Application Message to any other subscribed Client [MQTT-4.8.2-5].
+
+

+ +

·         +If the Server is in the process of sending a QoS 1 message to its +chosen subscribing Client and the connection to that Client breaks before the Server +has received an acknowledgement from the Client, the Server MAY wait for the +Client to reconnect and retransmit the message to that Client. If the Client'sSession +terminates before the Client reconnects, the Server SHOULD send the Application +Message to another Client that is subscribed to the same Shared Subscription. +It MAY attempt to send the message to another Client as soon as it loses its +connection to the first Client.
+
+

+ +

·         +If a Client responds with a PUBACK +or PUBREC containing a Reason Code of 0x80 or greater to a PUBLISH packet from +the Server, the Server MUST discard the Application Message and not attempt to +send it to any other Subscriber [MQTT-4.8.2-6].
+
+

+ +

·         +A Client is permitted to submit a second SUBSCRIBE request to a +Shared Subscription on a Session that's already subscribed to that Shared +Subscription. For example, it might do this to change the Requested QoS for its +subscription or because it was uncertain that the previous subscribe completed +before the previous connection was closed. This does not increase the number of +times that the Session is associated with the Shared Subscription, so the Session +will leave the Shared Subscription on its first UNSUBSCRIBE.
+
+

+ +

·         +Each Shared Subscription is independent from any other. It is possible +to have two Shared Subscriptions with overlapping filters. In such cases a +message that matches both Shared Subscriptions will be processed separately by +both of them. If a Client has a Shared Subscription and a Non‑shared Subscription +and a message matches both of them, the Client will receive a copy of the +message by virtue of it having the Non‑shared Subscription. A second copy +of the message will be delivered to one of the subscribers to the Shared +Subscription, and this could result in a second copy being sent to this Client.

+ +

 

+ +

4.9 Flow Control

+ +

Clients and Servers control the +number of unacknowledged PUBLISH packets they receive by using a Receive +Maximum value as described in section +3.1.2.11.4 and section 3.2.2.3.2. The Receive +Maximum establishes a send quota which is used to limit the number of PUBLISH +QOS > 0 packets which can be sent without receiving an PUBACK (for QoS 1) or +PUBCOMP (for QoS 2). The PUBACK and PUBCOMP replenish the quota in the manner +described below.

+ +

 

+ +

The Client or Server MUST +set its initial send quota to a non-zero value not exceeding the Receive +Maximum [MQTT-4.9.0-1].

+ +

 

+ +

Each time the Client or +Server sends a PUBLISH packet at QoS > 0, it decrements the send quota. If +the send quota reaches zero, the Client or Server MUST NOT send any more +PUBLISH packets with QoS > 0 [MQTT-4.9.0-2]. +It MAY continue to send PUBLISH packets with QoS 0, or it MAY choose to suspend +sending these as well. The Client and Server +MUST continue to process and respond to all other MQTT Control Packets even if +the quota is zero [MQTT-4.9.0-3].

+ +

 

+ +

The send quota is incremented by 1:

+ +

·         +Each time a PUBACK or PUBCOMP packet is received, regardless of +whether the PUBACK or PUBCOMP carried an error code.

+ +

·         +Each time a PUBREC packet is received with a Return Code of 0x80 +or greater.

+ +

 

+ +

The send quota is not incremented if it is already equal to +the initial send quota. The attempt to increment above the initial send quota +might be caused by the re-transmission of a PUBREL packet after a new Network +Connection is established.

+ +

 

+ +

Refer to section 3.3.4 for a +description of how Clients and Servers react if they are sent more PUBLISH +packets than the Receive Maximum allows.

+ +

 

+ +

The send quota and Receive Maximum value are not preserved +across Network Connections, and are re-initialized with each new Network +Connection as described above. They are not part of the session state.

+ +

 

+ +

4.10 Request / Response

+ +

Some applications or standards +might wish to run a Request/Response interaction over MQTT. This version of +MQTT includes three properties that can be used for this purpose:

+ +

·         +Response Topic, described in section +3.3.2.3.5

+ +

·         +Correlation Data, described in section +3.3.2.3.6

+ +

·         +Request Response Information, described in section 3.1.2.11.7

+ +

·         +Response Information, described in section 3.2.2.3.14

+ +

The following non-normative sections describe how these +properties can be used.

+ +

 

+ +

A Client sends a Request Message by publishing an +Application Message which has a Response Topic set as described in section 3.3.2.3.5. The Request can include a +Correlation Data property as described in section +3.3.2.3.6.

+ +

 

+ +

4.10.1 Basic Request Response (non-normative)

+ +

 Request/Response interaction proceeds as follows:

+ +

1.     An MQTT +Client (the Requester) publishes a Request Message to a topic. A Request +Message is an Application Message with a Response Topic.

+ +

2.     Another +MQTT Client (the Responder) has subscribed to a Topic Filter which matches the +Topic Name used when the Request Message was published. As a result, it receives +the Request Message. There could be multiple Responders subscribed to this +Topic Name or there could be none.

+ +

3.     The +Responder takes the appropriate action based on the Request Message, and then +publishes a Response Message to the Topic Name in the Response Topic property +that was carried in the Request Message.

+ +

4.     In typical +usage the Requester has subscribed to the Response Topic and thereby receives +the Response Message. However, some other Client might be subscribed to the +Response Topic in which case the Response Message will also be received and +processed by that Client. As with the Request Message, the topic on which the +Response Message is sent could be subscribed to by multiple Clients, or by +none.

+ +

 

+ +

If the Request Message contains a Correlation Data property, +the Responder copies this property into the Response Message and this is used +by the receiver of the Response Message to associate the Response Message with +the original request. The Response Message does not include a Response Topic +property.

+ +

 

+ +

The MQTT Server forwards the Response Topic and Correlation +Data Property in the Request Message and the Correlation Data in the Response +Message. The Server treats the Request Message and the Response Message like +any other Application Message.

+ +

 

+ +

The Requester normally subscribes to the Response Topic +before publishing a Request Message. If there are no subscribers to the +Response Topic when the Response Message is sent, the Response Message will not +be delivered to any Client.

+ +

 

+ +

The Request Message and Response Message can be of any QoS, +and the Responder can be using a Session with a non-zero Session Expiry +Interval. It is common to send Request Messages at QoS 0 and only when the +Responder is expected to be connected. However, this is not necessary.

+ +

 

+ +

The Responder can use a Shared Subscription to allow for a +pool of responding Clients. Note however that when using Shared Subscriptions +that the order of message delivery is not guaranteed between multiple Clients.

+ +

 

+ +

It is the responsibility of the Requester to make sure it +has the necessary authority to publish to the request topic, and to subscribe +to the Topic Name that it sets in the Response Topic property. It is the +responsibility of the Responder to make sure it has the authority to subscribe +to the request topic and publish to the Response Topic. While topic +authorization is outside of this specification, it is recommended that Servers +implement such authorization.

+ +

 

+ +

4.10.2 Determining a Response Topic value (non-normative)

+ +

Requesters can determine a Topic Name to use as their +Response Topic in any manner they choose including via local configuration. To +avoid clashes between different Requesters, it is desirable that the Response +Topic used by a Requester Client be unique to that Client. As the Requester and +Responder commonly need to be authorized to these topics, it can be an +authorization challenge to use a random Topic Name.

+ +

 

+ +

To help with this problem, this specification defines a +property in the CONNACK packet called Response Information. The Server can use +this property to guide the Client in its choice for the Response Topic to use. +This mechanism is optional for both the Client and the Server. At connect time, +the Client requests that the Server send a Response Information by setting the +Request Response Information property in the CONNECT packet. This causes the +Server to insert a Response Information property (a UTF-8 Encoded String) sent +in the CONNACK packet.

+ +

 

+ +

This specification does not define the contents of the +Response Information but it could be used to pass a globally unique portion of +the topic tree which is reserved for that Client for at least the lifetime of +its Session. Using this mechanism allows this configuration to be done once in +the Server rather than in each Client.

+ +

 

+ +

Refer to section 3.1.2.11.7 for the definition of the +Response Information.

+ +

 

+ +

4.11 Server redirection

+ +

A Server can request that the Client uses another Server by +sending CONNACK or DISCONNECT with Reason Codes 0x9C (Use another server), or +0x9D (Server moved) as described in section 4.13. +When sending one of these Reason Codes, the Server MAY also include a Server +Reference property to indicate the location of the Server or Servers the Client +SHOULD use.

+ +

 

+ +

The Reason Code 0x9C (Use another server) specifies that the +Client SHOULD temporarily switch to using another Server. The other Server is +either already known to the Client, or is specified using a Server Reference.

+ +

 

+ +

The Reason Code 0x9D (Server moved) specifies that the +Client SHOULD permanently switch to using another Server. The other Server is +either already known to the Client, or is specified using a Server Reference.

+ +

 

+ +

The Server Reference is a UTF-8 Encoded String. The value of +this string is a space separated list of references. The format of references +is not specified here.

+ +

 

+ +

Non-normative +comment

+ +

It is recommended that each +reference consists of a name optionally followed by a colon and a port number. +If the name contains a colon the name string can be enclosed within square +brackets (“[“ and ‘]”). A name enclosed by square brackets cannot contain the +right square bracket (“]”) character. This is used to represent an IPv6 literal +address which uses colon separators. This is a +simplified version of an URI authority as described in [RFC3986].

+ +

 

+ +

Non-normative comment

+ +

The name within a Server Reference +commonly represents a host name, DNS name [RFC1035], SRV +name [RFC2782] , or literal IP address. The value +following the colon separator is commonly a port number in decimal. This is not +needed where the port information comes from the name resolution (such as with +SRV) or is defaulted.

+ +

 

+ +

Non-normative comment

+ +

If multiple references are given, +the expectation is that that Client will choose one of them.

+ +

 

+ +

Non-normative +comment

+ +

Examples of the Server Reference +are:

+ +

 myserver.xyz.org +

+ +

 myserver.xyz.org:8883

+ +

 10.10.151.22:8883 +[fe80::9610:3eff:fe1c]:1883

+ +

 

+ +

The Server is allowed to not ever send a Server Reference, +and the Client is allowed to ignore a Server Reference. This feature can be +used to allow for load balancing, Server relocation, and Client provisioning to +a Server.

+ +

 

+ +

4.12 Enhanced +authentication

+ +

The MQTT CONNECT packet supports basic authentication of a +Network Connection using the User Name and Password fields. While these fields +are named for a simple password authentication, they can be used to carry other +forms of authentication such as passing a token as the Password.

+ +

 

+ +

Enhanced authentication extends this basic authentication to +include challenge / response style authentication. It might involve the +exchange of AUTH packets between the Client and the Server after the CONNECT +and before the CONNACK packets.

+ +

 

+ +

To begin an enhanced authentication, the Client includes an +Authentication Method in the CONNECT packet. This specifies the authentication +method to use. If the Server does not support +the Authentication Method supplied by the Client, it MAY send a CONNACK with a +Reason Code of 0x8C (Bad authentication method) or 0x87 (Not Authorized) as +described in section +4.13 and MUST close the Network +Connection [MQTT-4.12.0-1].

+ +

 

+ +

The Authentication Method is an agreement between the Client +and Server about the meaning of the data sent in the Authentication Data and +any of the other fields in CONNECT, and the exchanges and processing needed by +the Client and Server to complete the authentication.

+ +

 

+ +

Non-normative +comment

+ +

The Authentication Method is commonly +a SASL mechanism, and using such a registered name aids interchange. However, +the Authentication Method is not constrained to using registered SASL +mechanisms.

+ +

 

+ +

If the Authentication Method selected by the Client +specifies that the Client sends data first, the Client SHOULD include an +Authentication Data property in the CONNECT packet. This property can be used +to provide data as specified by the Authentication Method. The contents of the +Authentication Data are defined by the authentication method.

+ +

 

+ +

If the Server requires +additional information to complete the authentication, it can send an AUTH +packet to the Client. This packet MUST contain a Reason Code of 0x18 (Continue +authentication) [MQTT-4.12.0-2]. If the +authentication method requires the Server to send authentication data to the +Client, it is sent in the Authentication Data.

+ +

 

+ +

The Client responds to an +AUTH packet from the Server by sending a further AUTH packet. This packet MUST +contain a Reason Code of 0x18 (Continue authentication) [MQTT-4.12.0-3]. If the authentication method requires +the Client to send authentication data for the Server, it is sent in the Authentication +Data.

+ +

 

+ +

The Client and Server exchange AUTH packets as needed until +the Server accepts the authentication by sending a CONNACK with a Reason Code +of 0. If the acceptance of the authentication requires data to be sent to the +Client, it is sent in the Authentication Data.

+ +

 

+ +

The Client can close the connection at any point in this +process. It MAY send a DISCONNECT packet before doing so. The Server can reject the authentication at any point +in this process. It MAY send a CONNACK with a Reason Code of 0x80 or above as +described in section +4.13, and MUST close the Network +Connection [MQTT-4.12.0-4].

+ +

 

+ +

If the initial CONNECT +packet included an Authentication Method property then all AUTH packets, and +any successful CONNACK packet MUST include an Authentication Method Property +with the same value as in the CONNECT packet [MQTT-4.12.0-5].

+ +

 

+ +

The implementation of enhanced authentication is OPTIONAL +for both Clients and Servers. If the Client +does not include an Authentication Method in the CONNECT, the Server MUST NOT send +an AUTH packet, and it MUST NOT send an Authentication Method in the CONNACK +packet [MQTT-4.12.0-6]. If the Client does not include an Authentication +Method in the CONNECT, the Client MUST NOT send an AUTH packet to the Server +[MQTT-4.12.0-7].

+ +

 

+ +

If the Client does not include an Authentication Method in +the CONNECT packet, the Server SHOULD authenticate using some or all of the +information in the CONNECT packet, TLS session, and Network Connection.

+ +

 

+ +

Non-normative example showing +a SCRAM challenge

+ +

·         +Client to Server: CONNECT Authentication +Method="SCRAM-SHA-1" Authentication Data=client-first-data

+ +

·         +Server to Client: AUTH rc=0x18 Authentication +Method="SCRAM-SHA-1" Authentication Data=server-first-data

+ +

·         +Client to Server AUTH rc=0x18 Authentication Method="SCRAM-SHA-1" +Authentication Data=client-final-data

+ +

·         +Server to Client CONNACK rc=0 Authentication +Method="SCRAM-SHA-1" Authentication Data=server-final-data

+ +

 

+ +

Non-normative example +showing a Kerberos challenge

+ +

·         +Client to Server CONNECT Authentication Method="GS2-KRB5" +

+ +

·         +Server to Client AUTH rc=0x18 Authentication Method="GS2-KRB5" +

+ +

·         +Client to Server AUTH rc=0x18 Authentication Method="GS2-KRB5" +Authentication Data=initial context token

+ +

·         +Server to Client AUTH rc=0x18 Authentication Method="GS2-KRB5" +Authentication Data=reply context token

+ +

·         +Client to Server AUTH rc=0x18 Authentication +Method="GS2-KRB5"

+ +

·         +Server to Client CONNACK rc=0 Authentication Method="GS2-KRB5" +Authentication Data=outcome of authentication

+ +

 

+ +

4.12.1 Re-authentication

+ +

If the Client supplied an +Authentication Method in the CONNECT packet it can initiate a re-authentication +at any time after receiving a CONNACK. It does this by sending an AUTH packet +with a Reason Code of 0x19 (Re-authentication). The Client MUST set the Authentication +Method to the same value as the Authentication Method originally used to +authenticate the Network Connection [MQTT-4.12.1-1]. +If the authentication method requires Client data first, this AUTH packet +contains the first piece of authentication data as the Authentication Data.

+ +

 

+ +

The Server responds to this re-authentication request by +sending an AUTH packet to the Client with a Reason Code of 0x00 (Success) to +indicate that the re-authentication is complete, or a Reason Code of 0x18 +(Continue authentication) to indicate that more authentication data is needed. +The Client can respond with additional authentication data by sending an AUTH +packet with a Reason Code of 0x18 (Continue authentication). This flow +continues as with the original authentication until the re-authentication is complete +or the re-authentication fails.

+ +

 

+ +

If the re-authentication +fails, the Client or Server SHOULD send DISCONNECT with an appropriate Reason +Code as described in section 4.13, and MUST close +the Network Connection [MQTT-4.12.1-2].

+ +

 

+ +

During this re-authentication sequence, the flow of other +packets between the Client and Server can continue using the previous +authentication.

+ +

 

+ +

Non-normative +comment

+ +

The Server might limit the scope of +the changes the Client can attempt in a re-authentication by rejecting the +re-authentication. For instance, if the Server does not allow the User Name to +be changed it can fail any re-authentication attempt which changes the User +Name.

+ +

 

+ +

4.13 Handling errors

+ +

4.13.1 Malformed Packet and +Protocol Errors

+ +

Definitions of Malformed Packet and Protocol Errors are +contained in section 1.2 Terminology, some but not +all, of these error cases are noted throughout the specification. The rigor with +which a Client or Server checks an MQTT Control Packet it has received will be +a compromise between:

+ +

·         +The size of the Client or Server implementation.

+ +

·         +The capabilities that the implementation supports.

+ +

·         +The degree to which the receiver trusts the sender to send +correct MQTT Control Packets.

+ +

·         +The degree to which the receiver trusts the network to deliver +MQTT Control Packets correctly.

+ +

·         +The consequences of continuing to process a packet that is +incorrect.

+ +

 

+ +

If the sender is compliant with this specification it will +not send Malformed Packets or cause Protocol Errors. However, if a Client sends +MQTT Control Packets before it receives CONNACK, it might cause a Protocol +Error because it made an incorrect assumption about the Server capabilities. Refer +to section 3.1.4 CONNECT Actions.

+ +

 

+ +

The Reason Codes used for Malformed Packet and Protocol +Errors are:

+ +

·         +0x81           Malformed Packet

+ +

·         +0x82           Protocol Error

+ +

·         +0x93           Receive Maximum exceeded

+ +

·         +0x95           Packet too large

+ +

·         +0x9A           Retain not supported

+ +

·         +0x9B           QoS not supported

+ +

·         +0x9E           Shared Subscriptions not supported

+ +

·         +0xA1           Subscription Identifiers not supported

+ +

·         +0xA2           Wildcard Subscriptions not supported

+ +

 

+ +

When a Client detects a Malformed Packet or Protocol Error, and +a Reason Code is given in the specification, it SHOULD close the Network +Connection. In the case of an error in a AUTH packet it MAY send a DISCONNECT packet +containing the reason code, before closing the Network Connection. In the case +of an error in any other packet it SHOULD send a DISCONNECT packet containing +the reason code before closing the Network Connection. Use Reason Code 0x81 +(Malformed Packet) or 0x82 (Protocol Error) unless a more specific Reason Code +has been defined in section 3.14.2.1 Disconnect +Reason Code.

+ +

 

+ +

When a Server detects a +Malformed Packet or Protocol Error, and a Reason Code is given in the +specification, it MUST close the Network Connection [MQTT-4.13.1-1]. In the case of an error in a CONNECT +packet it MAY send a CONNACK packet containing the Reason Code, before closing +the Network Connection. In the case of an error in any other packet it SHOULD +send a DISCONNECT packet containing the Reason Code before closing the Network +Connection. Use Reason Code 0x81 (Malformed Packet) or 0x82 (Protocol Error) +unless a more specific Reason Code has been defined in section 3.2.2.2 - Connect Reason Code or in +section 3.14.2.1 – Disconnect Reason Code. +There are no consequences for other Sessions.

+ +

 

+ +

If either the Server or Client omits to check some feature +of an MQTT Control Packet, it might fail to detect an error, consequently it +might allow data to be damaged.

+ +

 

+ +

4.13.2 Other errors

+ +

Errors other than Malformed Packet and Protocol Errors +cannot be anticipated by the sender because the receiver might have constraints +which it has not communicated to the sender. A receiving Client or Server might +encounter a transient error, such as a shortage of memory, that prevents +successful processing of an individual MQTT Control Packet.

+ +

 

+ +

Acknowledgment packets PUBACK, PUBREC, PUBREL, PUBCOMP, +SUBACK, UNSUBACK with a Reason Code of 0x80 or greater indicate that the +received packet, identified by a Packet Identifier, was in error. There are no +consequences for other Sessions or other Packets flowing on the same Session.

+ +

 

+ +

The CONNACK and DISCONNECT +packets allow a Reason Code of 0x80 or greater to indicate that the Network +Connection will be closed. If a Reason Code of 0x80 or greater is specified, +then the Network Connection MUST be closed whether or not the CONNACK or +DISCONNECT is sent [MQTT-4.13.2-1]. +Sending of one of these Reason Codes does not have consequence for any other +Session.

+ +

 

+ +

If the Control Packet contains multiple errors the receiver +of the Packet can validate the Packet in any order and take the appropriate +action for any of the errors found.

+ +

 

+ +

Refer to section 5.4.9 for information about +handling Disallowed Unicode code points.

+ +
+ +

5      +Security (non-normative)

+ +
+ +

5.1 Introduction

+ +

MQTT is a transport protocol specification for message +transmission, allowing implementers a choice of network, privacy, +authentication and authorization technologies. Since the exact security +technologies chosen will be context specific, it is the implementer's responsibility +to include the appropriate features as part of their design.

+ +

 

+ +

MQTT Implementations will likely need to keep pace with an +evolving security landscape.

+ +

 

+ +

This Chapter provides general implementation guidance so as +not to restrict choices available and is therefore non-normative. This should +not detract from its importance.

+ +

 

+ +

It is strongly recommended that Server implementations that +offer TLS [RFC5246] should use TCP +port 8883 (IANA service name: secure-mqtt).

+ +

 

+ +

There are a number of threats that solution providers should +consider. For example:

+ + + +

 

+ +

MQTT solutions are often deployed in hostile communication +environments. In such cases, implementations will often need to provide +mechanisms for:

+ + + +

 

+ +

In addition to technical security issues there could also be +geographic (e.g. U.S.-EU Privacy Shield Framework [USEUPRIVSH]), +industry specific (e.g. PCI DSS [PCIDSS]) +and regulatory considerations (e.g. Sarbanes-Oxley [SARBANES]).

+ +

+ +

5.2 MQTT solutions: security +and certification

+ +

An implementation might want to provide conformance with +specific industry security standards such as NIST Cyber Security Framework [NISTCSF], PCI-DSS [PCIDSS]), +FIPS-140-2 [FIPS1402] and NSA Suite B [NSAB].

+ +

+ +

Guidance on using MQTT within the NIST Cyber Security +Framework [NISTCSF] can be found +in the MQTT supplemental publication, MQTT and the NIST Framework for Improving +Critical Infrastructure Cybersecurity [MQTTNIST]. The +use of industry proven, independently verified and certified technologies will +help meet compliance +requirements.

+ +

 

+ +

5.3 Lightweight crytography and constrained devices

+ +

Advanced Encryption Standard [AES] is the +most widely adopted encryption algorithm. There is hardware support for AES in +many processors, but not commonly for embedded processors. The encryption algorithm +ChaCha20 [CHACHA20] encrypts and decrypts much faster +in software, but is not as widely available as AES.

+ +

 

+ +

ISO 29192 [ISO29192] makes +recommendations for cryptographic primitives specifically tuned to perform on +constrained “low end” devices.

+ +

+ +

5.4 Implementation notes

+ +

There are many security concerns to consider when +implementing or using MQTT. The following section should not be considered a +“check list”.

+ +

 

+ +

An implementation might want to achieve some, or all, of the +following:

+ +

 

+ +

5.4.1 Authentication of +Clients by the Server

+ +

The CONNECT packet contains User Name and Password fields. +Implementations can choose how to make use of the content of these fields. They +may provide their own authentication mechanism, use an external authentication +system such as LDAP [RFC4511] or OAuth [RFC6749] +tokens, or leverage operating system authentication mechanisms.

+ +

 

+ +

MQTT v5.0 provides an enhanced authentication mechanism as +described in section 4.12. Using this +requires support for it in both the Client and Server.

+ +

 

+ +

Implementations passing authentication data in clear text, +obfuscating such data elements or requiring no authentication data should be +aware this can give rise to Man-in-the-Middle and replay attacks. Section 5.4.5 introduces approaches to +ensure data privacy.

+ +

 

+ +

A Virtual Private Network (VPN) between the Clients and +Servers can provide confidence that data is only being received from authorized +Clients.

+ +

 

+ +

Where TLS [RFC5246] is used, TLS +Certificates sent from the Client can be used by the Server to authenticate the +Client.

+ +

 

+ +

An implementation might allow for authentication where the +credentials are sent in an Application Message from the Client to the Server.

+ +

 

+ +

5.4.2 Authorization of Clients +by the Server

+ +

If +a Client has been successfully authenticated, a Server implementation should +check that it is authorized before accepting its connection.

+ +

 

+ +

Authorization may be based on information provided by the +Client such as User Name, the hostname/IP address of the Client, or the outcome +of authentication mechanisms.

+ +

 

+ +

In particular, the implementation should check that the +Client is authorized to use the Client Identifier as this gives access to the +MQTT Session State (described in section 4.1). +This authorization check is to protect against the case where one Client, +accidentally or maliciously, provides a Client Identifier that is already being +used by some other Client.

+ +

 

+ +

An implementation should provide access controls that take +place after CONNECT to restrict the Clients ability to publish to particular +Topics or to subscribe using particular Topic Filters. An implementation should +consider limiting access to Topic Filters that have broad scope, such as the # +Topic Filter.

+ +

 

+ +

5.4.3 +Authentication of the Server by the Client

+ +

The MQTT protocol is not trust symmetrical. When using basic +authentication, there is no mechanism for the Client to authenticate the +Server. Some forms of extended authentication do allow for mutual +authentication.

+ +

 

+ +

Where TLS [RFC5246] is used, TLS +Certificates sent from the Server can be used by the Client to authenticate the +Server. Implementations providing MQTT service for multiple hostnames from a +single IP address should be aware of the Server Name Indication extension to TLS +defined in section 3 of [RFC6066].This allows a Client +to tell the Server the hostname of the Server it is trying to connect to.

+ +

 

+ +

An implementation might allow for authentication where the +credentials are sent in an Application Message from the Server to the Client. MQTT +v5.0 provides an enhanced authentication mechanism as described in section 4.12., which can be used to Authenticate +the Server to the Client. Using this requires support for it in both the Client +and Server.

+ +

 

+ +

A VPN between Clients and Servers can provide confidence +that Clients are connecting to the intended Server.

+ +

 

+ +

5.4.4 Integrity of Application +Messages and MQTT Control Packets

+ +

Applications can independently include hash values in their +Application Messages. This can provide integrity of the contents of Publish packets +across the network and at rest.

+ +

 

+ +

TLS [RFC5246] +provides hash algorithms to verify the integrity of data sent over the network.

+ +

 

+ +

The use of VPNs to connect Clients and Servers can provide +integrity of data across the section of the network covered by a VPN.

+ +

 

+ +

5.4.5 Privacy of Application Messages and MQTT +Control Packets

+ +

TLS [RFC5246] can provide encryption +of data sent over the network. There are valid TLS cipher suites that include a +NULL encryption algorithm that does not encrypt data. To ensure privacy Clients +and Servers should avoid these cipher suites.

+ +

 

+ +

An application might independently encrypt the contents of +its Application Messages. This could provide privacy of the Application Message +both over the network and at rest. This would not provide privacy for other Properties +of the Application Message such as Topic Name.

+ +

 

+ +

Client and Server implementations can provide encrypted +storage for data at rest such as Application Messages stored as part of a +Session.

+ +

 

+ +

The use of VPNs to connect Clients and Servers can provide +privacy of data across the section of the network covered by a VPN.

+ +

 

+ +

5.4.6  Non-repudiation of message +transmission

+ +

Application designers might need to consider appropriate +strategies to achieve end to end non-repudiation.

+ +

 

+ +

5.4.7 Detecting compromise of +Clients and Servers

+ +

Client and Server implementations using TLS [RFC5246] should provide +capabilities to ensure that any TLS certificates provided when initiating a TLS connection are associated with the hostname of the +Client connecting or Server being connected to.

+ +

 

+ +

Client and Server implementations using TLS can choose to +provide capabilities to check Certificate Revocation Lists (CRLs [RFC5280]) and Online Certificate Status Protocol (OSCP) [RFC6960] +to prevent revoked certificates from being used.

+ +

 

+ +

Physical deployments might combine tamper-proof hardware +with the transmission of specific data in Application Messages. For example, a +meter might have an embedded GPS to ensure it is not used in an unauthorized +location. +[IEEE8021AR] is a standard for implementing +mechanisms to authenticate a device’s identity using a cryptographically bound +identifier.

+ +

+ +

5.4.8 Detecting abnormal +behaviors

+ +

Server implementations might monitor Client behavior to +detect potential security incidents. For example:

+ +

·         +Repeated connection attempts

+ +

·         +Repeated authentication attempts

+ +

·         +Abnormal termination of connections

+ +

·         +Topic scanning (attempts to send or subscribe to many topics)

+ +

·         +Sending undeliverable messages (no subscribers to the topics)

+ +

·         +Clients that connect but do not send data

+ +

 

+ +

Server implementations might close +the Network Connection of Clients that breach its security rules.

+ +

 

+ +

Server implementations detecting unwelcome behavior might +implement a dynamic block list based on identifiers such as IP address or Client +Identifier.

+ +

 

+ +

Deployments might use network-level controls (where +available) to implement rate limiting or blocking based on IP address or other +information.

+ +

 

+ +

5.4.9 Handling of Disallowed Unicode code +points

+ +

Section 1.5.4 describes the +Disallowed Unicode code points, which should not be included in a UTF-8 Encoded +String. A Client or Server implementation can choose whether to validate that +these code points are not used in UTF-8 Encoded Strings such as the Topic Name +or Properties.

+ +

 

+ +

If the Server does not validate the code points in a UTF-8 +Encoded String but a subscribing Client does, then a second Client might be +able to cause the subscribing Client to close the Network Connection by +publishing on a Topic Name or using Properties that contain a Disallowed +Unicode code point. This section recommends some steps that can be taken to +prevent this problem.

+ +

 

+ +

A similar problem can occur when the Client validates that +the payload matches the Payload Format Indicator and the Server does not.  The +considerations and remedies for this are similar to those for handling +Disallowed Unicode code points.

+ +

 

+ +

5.4.9.1 Considerations for the use of Disallowed Unicode +code points

+ +

An implementation would normally choose to validate UTF-8 +Encoded strings, checking that the Disallowed Unicode code points are not used. +This avoids implementation difficulties such as the use of libraries that are +sensitive to these code points, it also protects applications from having to +process them.

+ +

 

+ +

Validating that these code points are not used removes some +security exposures. There are possible security exploits which use control +characters in log files to mask entries in the logs or confuse the tools which +process log files.  The Unicode Noncharacters are commonly used as special +markers and allowing them into UTF-8 Encoded Strings could permit such +exploits. 

+ +

 

+ +

5.4.9.2 Interactions between +Publishers and Subscribers

+ +

The publisher of an Application Message normally expects +that the Servers will forward the message to subscribers, and that these +subscribers are capable of processing the messages.

+ +

These are some conditions under which a publishing Client +can cause the subscribing Client to close the Network Connection. Consider a +situation where:

+ +

·         +A Client publishes an Application Message using a Topic Name +containing one of the Disallowed Unicode code points.

+ +

·         +The publishing Client library allows the Disallowed Unicode code +point to be used in a Topic Name rather than rejecting it.

+ +

·         +The publishing Client is authorized to send the publication.

+ +

·         +A subscribing Client is authorized to use a Topic Filter which +matches the Topic Name. Note that the Disallowed Unicode code point might occur +in a part of the Topic Name matching a wildcard character in the Topic Filter.

+ +

·         +The Server forwards the message to the matching subscriber rather +than disconnecting the publisher.

+ +

·         +In this case the subscribing Client might:

+ +

o    +Close the Network Connection because it does not allow the use of +Disallowed Unicode code points, possibly sending a DISCONNECT before doing so.  +For QoS 1 and QoS 2 messages this might cause the Server to send the message +again, causing the Client to close the Network Connection again.

+ +

o    +Reject the Application Message by sending a Reason Code greater +than or equal to 0x80 in a PUBACK (QoS 1) or PUBREC (QoS 2).

+ +

o    +Accept the Application Message but fail to process it because it +contains one of the Disallowed Unicode code points.

+ +

o    +Successfully process the Application Message.

+ +

 

+ +

The potential for the Client to close the Network Connection +might go unnoticed until a publisher uses one of the Disallowed Unicode code +points.

+ +

 

+ +

5.4.9.3  Remedies

+ +

If there is a possibility that a Disallowed Unicode code +point could be included in a Topic Name or other Properties delivered to a +Client, the solution owner can adopt one of the following suggestions:

+ +

1)    Change the +Server implementation to one that rejects UTF-8 Encoded Strings containing a +Disallowed Unicode code point either by sending a Reason Code greater than or +equal to 0x80 or closing the Network Connection.

+ +

2)    Change the +Client library used by the subscribers to one that tolerates the use of +Disallowed Code points. The client can either process or discard messages with +UTF-8 Encoded Strings that contain Disallowed Unicode code points so long as it +continues the protocol.

+ +

 

+ +

5.4.10 Other security +considerations

+ +

If Client or Server TLS certificates are lost or it is +considered that they might be compromised they should be revoked (utilizing +CRLs [RFC5280] and/or OSCP [RFC6960]).

+ +

 

+ +

Client or Server authentication credentials, such as User +Name and Password, that are lost or considered compromised should be revoked +and/or reissued.

+ +

 

+ +

In the case of long lasting connections:

+ +

·         +Client and Server implementations using TLS [RFC5246] +should allow for session renegotiation to establish new cryptographic +parameters (replace session keys, change cipher suites, change authentication +credentials).

+ +

·         +Servers may close the Network Connection of Clients and require +them to re-authenticate with new credentials.

+ +

·         +Servers may require their Client to reauthenticate periodically +using the mechanism described in section 4.12.1.

+ +

 

+ +

Constrained devices and Clients on constrained networks can +make use of TLS [RFC5246] session resumption, in order +to reduce the costs of reconnecting TLS [RFC5246] +sessions.

+ +

 

+ +

Clients connected to a Server have a transitive trust +relationship with other Clients connected to the same Server and who have +authority to publish data on the same topics.

+ +

 

+ +

5.4.11 Use of SOCKS

+ +

Implementations of Clients should be aware that some +environments will require the use of SOCKSv5 [RFC1928] +proxies to make outbound Network Connections. Some MQTT implementations could +make use of alternative secured tunnels (e.g. SSH) through the use of SOCKS. +Where implementations choose to use SOCKS, they should support both anonymous +and User Name, Password authenticating SOCKS proxies. In the latter case, +implementations should be aware that SOCKS authentication might occur in +plain-text and so should avoid using the same credentials for connection to a +MQTT Server.

+ +

+ +

5.4.12 Security profiles

+ +

Implementers and solution designers might wish to consider +security as a set of profiles which can be applied to the MQTT protocol. An +example of a layered security hierarchy is presented below.

+ +

 

+ +

5.4.12.1 Clear communication +profile

+ +

When using the clear communication profile, the MQTT +protocol runs over an open network with no additional secure communication +mechanisms in place.

+ +

 

+ +

5.4.12.2 Secured network +communication profile

+ +

When using the secured network communication profile, the +MQTT protocol runs over a physical or virtual network which has security +controls e.g., VPNs or physically secure network.

+ +

 

+ +

5.4.12.3 Secured transport +profile

+ +

When using the secured transport profile, the MQTT protocol +runs over a physical or virtual network and using TLS [RFC5246] +which provides authentication, integrity and privacy.

+ +

 

+ +

TLS [RFC5246] Client authentication +can be used in addition to – or in place of – MQTT Client authentication as +provided by the User Name and Password fields.

+ +

+ +

5.4.12.4 Industry specific security +profiles

+ +

It is anticipated that the MQTT protocol will be designed +into industry specific application profiles, each defining a threat model and +the specific security mechanisms to be used to address these threats. Recommendations +for specific security mechanisms will often be taken from existing works +including:

+ +

 

+ +

[NISTCSF] NIST +Cyber Security Framework

+ +

[NIST7628] NISTIR +7628 Guidelines for Smart Grid Cyber Security

+ +

[FIPS1402] Security +Requirements for Cryptographic Modules (FIPS PUB 140-2)

+ +

[PCIDSS] PCI-DSS +Payment Card Industry Data Security Standard

+ +

[NSAB] NSA +Suite B Cryptography

+ +

 

+ +
+ +

6      Using +WebSocket as a network transport

+ +
+ +

If MQTT is transported over a +WebSocket [RFC6455] connection, the following conditions apply:

+ +

·         +MQTT Control Packets MUST be sent +in WebSocket binary data frames. If any other type of data frame is received +the recipient MUST close the Network Connection [MQTT-6.0.0-1].

+ +

·         +A single WebSocket data frame can +contain multiple or partial MQTT Control Packets. The receiver MUST NOT assume +that MQTT Control Packets are aligned on WebSocket frame boundaries [MQTT-6.0.0-2].

+ +

·         +The Client MUST include “mqtt” in +the list of WebSocket Sub Protocols it offers [MQTT-6.0.0-3]. +

+ +

·         +The WebSocket Subprotocol name +selected and returned by the Server MUST be “mqtt” [MQTT-6.0.0-4].

+ +

·         +The WebSocket URI used to connect +the Client and Server has no impact on the MQTT protocol.

+ +

 

+ +

6.1  IANA considerations

+ +

This +specification requests IANA to modify the registration of the WebSocket MQTT +sub-protocol under the “WebSocket Subprotocol Name” registry with the following +data:

+ +

 

+ +

Figure 6.6‑1 +- IANA WebSocket Identifier

+ + + + + + + + + + + + + + +
+

Subprotocol + Identifier

+
+

mqtt

+
+

Subprotocol + Common Name

+
+

mqtt

+
+

Subprotocol + Definition

+
+

http://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html

+
+ +

 

+ +
+ +

7      Conformance

+ +
+ +

The MQTT specification defines conformance for MQTT Client +implementations and MQTT Server implementations. An MQTT implementation can +conform as both an MQTT Client and an MQTT Server.

+ +

 

+ +

7.1 Conformance clauses

+ +

7.1.1 MQTT Server +conformance clause

+ +

Refer to Server in the Terminology +section for a definition of Server.

+ +

 

+ +

An MQTT Server conforms to this specification only if it +satisfies all the statements below:

+ +

1.     The format +of all MQTT Control Packets that the Server sends matches the format described +in Chapter 2 and Chapter 3.

+ +

2.     It follows +the Topic matching rules described in section 4.7 +and the Subscription rules in section 4.8.

+ +

3.     +It satisfies the MUST level requirements in the following +chapters that are identified except for those that only apply to the Client:

+ +

·         +Chapter 1 - Introduction

+ +

·         +Chapter 2 - MQTT Control Packet +format

+ +

·         +Chapter 3 - MQTT Control Packets

+ +

·         +Chapter 4 - Operational behavior

+ +

·         +Chapter 6 - Using WebSocket as a +network transport

+ +

4.     It does +not require the use of any extensions defined outside of the specification in +order to interoperate with any other conformant implementation.

+ +

 

+ +

7.1.2 MQTT Client +conformance clause

+ +

Refer to Client in the Terminology +section for a definition of Client.

+ +

 

+ +

An MQTT Client conforms to this specification only if it +satisfies all the statements below:

+ +

1.     The format +of all MQTT Control Packets that the Client sends matches the format described +in Chapter 2 and Chapter 3.

+ +

2.     +It satisfies the MUST level requirements in the following +chapters that are identified except for those that only apply to the Server:

+ +

·         +Chapter 1 - Introduction

+ +

·         +Chapter 2 - MQTT Control Packet +format

+ +

·         +Chapter 3 - MQTT Control Packets

+ +

·         +Chapter 4 - Operational behavior

+ +

·         +Chapter 6 - Using WebSocket as a +network transport

+ +

3.     It does +not require the use of any extensions defined outside of the specification in +order to interoperate with any other conformant implementation.

+ +

 

+ +
+ +

Appendix A. Acknowledgments

+ +
+ +

The TC +owes special thanks to Dr. Andy Stanford-Clark and Arlen Nipper as the original +inventors of the MQTT protocol and for their continued support with the +standardization process.

+ +

 

+ +

The TC wishes +to thank Brian Raymor (formerly of Microsoft) for his work as co-chairman of +the MQTT TC during much of the development of the version 5.0 standard.

+ +

 

+ +

The +following individuals were members of the OASIS Technical Committee during the +creation of this standard and their contributions are gratefully acknowledged:

+ +

 

+ +

Participants:

+ +

·         +Senthil Nathan Balasubramaniam (Infiswift)

+ +

·         +Dr. Andrew Banks, editor (IBM)

+ +

·         +Ken Borgendale, editor (IBM)

+ +

·         +Ed Briggs, editor (Microsoft)

+ +

·         +Raphael Cohn (Individual)

+ +

·         +Richard Coppen, chairman (IBM)

+ +

·         +William Cox (Individual)

+ +

·         +Ian Craggs , secretary (IBM)

+ +

·         +Konstantin Dotchkoff (Microsoft)

+ +

·         +Derek Fu (IBM)

+ +

·         +Rahul Gupta, editor (IBM)

+ +

·         +Stefan Hagen (Individual)

+ +

·         +David Horton (Solace Systems)

+ +

·         +Alex Kritikos (Software AG, Inc.)

+ +

·         +Jonathan Levell (IBM)

+ +

·         +Shawn McAllister (Solace Systems)

+ +

·         +William McLane (TIBCO Software Inc.)

+ +

·         +Peter Niblett (IBM)

+ +

·         +Dominik Obermaier (dc-square GmbH)

+ +

·         +Nicholas O'Leary (IBM)

+ +

·         +Brian Raymor (Microsoft)

+ +

·         +Andrew Schofield (IBM)

+ +

·         +Tobias Sommer (Cumulocity)

+ +

·         +Joe Speed (IBM)

+ +

·         +Dr Andy Stanford-Clark (IBM)

+ +

·         +Allan Stockdill-Mander (IBM)

+ +

·         +Stehan Vaillant (Cumulocity)

+ +

 

+ +

For a list of those who contributed to earlier versions of +MQTT refer to Appendix A in the MQTT v3.1.1 specification [MQTTV311]. +

+ +

 

+ +
+ +

Appendix B. Mandatory normative +statement (non-normative)

+ +
+ +

This Appendix is non-normative and is provided as a +convenient summary of the numbered conformance statements found in the main +body of this document. Refer to Chapter 7 for a +definitive list of conformance requirements.

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Normative Statement Number

+
+

Normative Statement

+
+

[MQTT-1.5.4-1]

+
+

The character data in a UTF-8 + Encoded String MUST be well-formed UTF-8 as defined by the Unicode + specification [Unicode] and restated in RFC 3629 [RFC3629]. In particular, + the character data MUST NOT include encodings of code points between U+D800 + and U+DFFF.

+
+

[MQTT-1.5.4-2]

+
+

A UTF-8 Encoded String MUST NOT + include an encoding of the null character U+0000.

+
+

[MQTT-1.5.4-3]

+
+

A UTF-8 encoded sequence 0xEF + 0xBB 0xBF is always interpreted as U+FEFF ("ZERO WIDTH NO-BREAK + SPACE") wherever it appears in a string and MUST NOT be skipped over or + stripped off by a packet receiver.

+
+

[MQTT-1.5.5-1]

+
+

The encoded value MUST use the + minimum number of bytes necessary to represent the value.

+
+

[MQTT-1.5.7-1]

+
+

Both strings MUST comply with + the requirements for UTF-8 Encoded Strings.

+
+

[MQTT-2.1.3-1]

+
+

Where a flag bit is marked as + “Reserved” it is reserved for future use and MUST be set to the value listed.

+
+

[MQTT-2.2.1-2]

+
+

A PUBLISH packet MUST NOT + contain a Packet Identifier if its QoS value is set to 0.

+
+

[MQTT-2.2.1-3]

+
+

Each time a Client sends a new + SUBSCRIBE, UNSUBSCRIBE,or PUBLISH (where QoS > 0) MQTT Control Packet it + MUST assign it a non-zero Packet Identifier that is currently unused.

+
+

[MQTT-2.2.1-4]

+
+

Each time a Server sends a new + PUBLISH (with QoS > 0) MQTT Control Packet it MUST assign it a non zero + Packet Identifier that is currently unused.

+
+

[MQTT-2.2.1-5]

+
+

A PUBACK, PUBREC, PUBREL, or + PUBCOMP packet MUST contain the same Packet Identifier as the PUBLISH packet + that was originally sent.

+
+

[MQTT-2.2.1-6]

+
+

A SUBACK and UNSUBACK MUST + contain the Packet Identifier that was used in the corresponding SUBSCRIBE + and UNSUBSCRIBE packet respectively.

+
+

[MQTT-2.2.2-1]

+
+

If there are no properties, this + MUST be indicated by including a Property Length of zero.

+
+

[MQTT-3.1.0-1]

+
+

After a Network Connection is + established by a Client to a Server, the first packet sent from the Client to + the Server MUST be a CONNECT packet.

+
+

[MQTT-3.1.0-2]

+
+

The Server MUST process a second + CONNECT packet sent from a Client as a Protocol Error and close the Network + Connection.

+
+

[MQTT-3.1.2-1]

+
+

The protocol name MUST be the + UTF-8 String "MQTT". If the Server does not want to accept the CONNECT, + and wishes to reveal that it is an MQTT Server it MAY send a CONNACK packet + with Reason Code of 0x84 (Unsupported Protocol Version), and then it MUST + close the Network Connection.

+
+

[MQTT-3.1.2-2]

+
+

If the Protocol Version is not 5 + and the Server does not want to accept the CONNECT packet, the Server MAY + send a CONNACK packet with Reason Code 0x84 (Unsupported Protocol Version) + and then MUST close the Network Connection

+
+

[MQTT-3.1.2-3]

+
+

The Server MUST validate that + the reserved flag in the CONNECT packet is set to 0.

+
+

[MQTT-3.1.2-4]

+
+

If a CONNECT packet is received + with Clean Start is set to 1, the Client and Server MUST discard any existing + Session and start a new Session.

+
+

[MQTT-3.1.2-5]

+
+

If a CONNECT packet is received + with Clean Start set to 0 and there is a Session associated with the Client + Identifier, the Server MUST resume communications with the Client based on + state from the existing Session.

+
+

[MQTT-3.1.2-6]

+
+

If a CONNECT packet is received + with Clean Start set to 0 and there is no Session associated with the Client + Identifier, the Server MUST create a new Session.

+
+

[MQTT-3.1.2-7]

+
+

If the Will Flag is set to 1 + this indicates that, a Will Message MUST be stored on the Server and associated + with the Session.

+
+

[MQTT-3.1.2-8]

+
+

The Will Message MUST be published + after the Network Connection is subsequently closed and either the Will Delay + Interval has elapsed or the Session ends, unless the Will Message has been + deleted by the Server on receipt of a DISCONNECT packet with Reason Code 0x00 + (Normal disconnection) or a new Network Connection for the ClientID is opened + before the Will Delay Interval has elapsed.

+
+

[MQTT-3.1.2-9]

+
+

If the Will Flag is set to 1, + the Will QoS and Will Retain fields in the Connect Flags will be used by the + Server, and the Will Properties, Will Topic and Will Message fields MUST be + present in the Payload.

+
+

[MQTT-3.1.2-10]

+
+

The Will Message MUST be removed + from the stored Session State in the Server once it has been published or the + Server has received a DISCONNECT packet with a Reason Code of 0x00 (Normal + disconnection) from the Client.

+
+

[MQTT-3.1.2-11]

+
+

If the Will Flag is set to 0, + then the Will QoS MUST be set to 0 (0x00).

+
+

[MQTT-3.1.2-12]

+
+

If the Will Flag is set to 1, the + value of Will QoS can be 0 (0x00), 1 (0x01), or 2 (0x02).

+
+

[MQTT-3.1.2-13]

+
+

If the Will Flag is set to 0, + then Will Retain MUST be set to 0.

+
+

[MQTT-3.1.2-14]

+
+

If the Will Flag is set to 1 and + Will Retain is set to 0, the Server MUST publish the Will Message as a + non-retained message.

+
+

[MQTT-3.1.2-15]

+
+

If the Will Flag is set to 1 and + Will Retain is set to 1, the Server MUST publish the Will Message as a + retained message.

+
+

[MQTT-3.1.2-16]

+
+

If the User Name Flag is set to + 0, a User Name MUST NOT be present in the Payload.

+
+

[MQTT-3.1.2-17]

+
+

If the User Name Flag is set to + 1, a User Name MUST be present in the Payload.

+
+

[MQTT-3.1.2-18]

+
+

If the Password Flag is set to + 0, a Password MUST NOT be present in the Payload.

+
+

[MQTT-3.1.2-19]

+
+

If the Password Flag is set to + 1, a Password MUST be present in the Payload.

+
+

[MQTT-3.1.2-20]

+
+

If Keep Alive is non-zero and in + the absence of sending any other MQTT Control Packets, the Client MUST send a + PINGREQ packet.

+
+

[MQTT-3.1.2-21]

+
+

If the Server returns a Server + Keep Alive on the CONNACK packet, the Client MUST use that value instead of + the value it sent as the Keep Alive.

+
+

[MQTT-3.1.2-22]

+
+

If the Keep Alive value is + non-zero and the Server does not receive an MQTT Control Packet from the + Client within one and a half times the Keep Alive time period, it MUST close + the Network Connection to the Client as if the network had failed.

+
+

[MQTT-3.1.2-23]

+
+

The Client and Server MUST store + the Session State after the Network Connection is closed if the Session + Expiry Interval is greater than 0.

+
+

[MQTT-3.1.2-24]

+
+

The Server MUST NOT + send packets exceeding Maximum Packet Size to the Client.

+
+

[MQTT-3.1.2-25]

+
+

Where a Packet is too + large to send, the Server MUST discard it without sending it and then behave + as if it had completed sending that Application Message.

+
+

[MQTT-3.1.2-26]

+
+

The Server MUST NOT send a Topic + Alias in a PUBLISH packet to the Client greater than Topic Alias Maximum.

+
+

[MQTT-3.1.2-27]

+
+

If Topic Alias Maximum is absent + or zero, the Server MUST NOT send any Topic Aliases to the.

+
+

[MQTT-3.1.2-28]

+
+

A value of 0 indicates that the + Server MUST NOT return Response Information.

+
+

[MQTT-3.1.2-29]

+
+

If the value of Request Problem + Information is 0, the Server MAY return a Reason String or User Properties on + a CONNACK or DISCONNECT packet, but MUST NOT send a Reason String or User + Properties on any packet other than PUBLISH, CONNACK, or DISCONNECT.

+
+

[MQTT-3.1.2-30]

+
+

If a Client sets an + Authentication Method in the CONNECT, the Client MUST NOT send any packets + other than AUTH or DISCONNECT packets until it has received a CONNACK packet.

+
+

[MQTT-3.1.3-1]

+
+

The Payload of the CONNECT + packet contains one or more length-prefixed fields, whose presence is + determined by the flags in the Variable Header. These fields, if present, + MUST appear in the order Client Identifier, Will Topic, Will Message, User + Name, Password.

+
+

[MQTT-3.1.3-2]

+
+

The ClientID MUST be used by + Clients and by Servers to identify state that they hold relating to this MQTT + Session between the Client and the Server.

+
+

[MQTT-3.1.3-3]

+
+

The ClientID MUST be present and + is the first field in the CONNECT packet Payload.

+
+

[MQTT-3.1.3-4]

+
+

The ClientID MUST be a UTF-8 + Encoded String.

+
+

[MQTT-3.1.3-5]

+
+

The Server MUST allow ClientID’s + which are between 1 and 23 UTF-8 encoded bytes in length, and that contain + only the characters
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".

+
+

[MQTT-3.1.3-6]

+
+

A Server MAY allow a Client to + supply a ClientID that has a length of zero bytes, however if it does so the + Server MUST treat this as a special case and assign a unique ClientID to that + Client.

+
+

[MQTT-3.1.3-7]

+
+

It MUST then process the CONNECT + packet as if the Client had provided that unique ClientID, and MUST return + the Assigned Client Identifier in the CONNACK packet.

+
+

[MQTT-3.1.3-8]

+
+

If the Server rejects the ClientID + it MAY respond to the CONNECT packet with a CONNACK using Reason Code 0x85 + (Client Identifier not valid) as described in section 4.13 Handling errors, + and then it MUST close the Network Connection.

+
+

[MQTT-3.1.3-9]

+
+

If a new Network Connection to + this Session is made before the Will Delay Interval has passed, the Server MUST + NOT send the Will Message.

+
+

[MQTT-3.1.3-10]

+
+

The Server MUST maintain the + order of User Properties when forwarding the Application Message.

+
+

[MQTT-3.1.3-11]

+
+

The Will Topic MUST be a UTF-8 Encoded + String.

+
+

[MQTT-3.1.3-12]

+
+

If the User Name Flag is set to 1, + the User Name is the next field in the Payload. The User Name MUST be a UTF-8 + Encoded String.

+
+

[MQTT-3.1.4-1]

+
+

The Server MUST validate that + the CONNECT packet matches the format described in section 3.1 and close the + Network Connection if it does not match.

+
+

[MQTT-3.1.4-2]

+
+

The Server MAY check that the + contents of the CONNECT packet meet any further restrictions and SHOULD + perform authentication and authorization checks. If any of these checks fail, + it MUST close the Network Connection.

+
+

[MQTT-3.1.4-3]

+
+

If the ClientID represents a + Client already connected to the Server, the Server sends a DISCONNECT packet + to the existing Client with Reason Code of 0x8E (Session taken over) as + described in section 4.13 and MUST close the Network Connection of the + existing Client.

+
+

[MQTT-3.1.4-4]

+
+

The Server MUST perform the + processing of Clean Start.

+
+

[MQTT-3.1.4-5]

+
+

The Server MUST acknowledge the + CONNECT packet with a CONNACK packet containing a 0x00 (Success) Reason Code.

+
+

[MQTT-3.1.4-6]

+
+

If the Server rejects the + CONNECT, it MUST NOT process any data sent by the Client after the CONNECT + packet except AUTH packets.

+
+

[MQTT-3.2.0-1]

+
+

The Server MUST send a CONNACK + with a 0x00 (Success) Reason Code before sending any Packet other than AUTH.

+
+

[MQTT-3.2.0-2]

+
+

The Server MUST NOT send more + than one CONNACK in a Network Connection.

+
+

[MQTT-3.2.2-1]

+
+

Byte 1 is the "Connect Acknowledge + Flags". Bits 7-1 are reserved and MUST be set to 0.

+
+

[MQTT-3.2.2-2]

+
+

If the Server accepts a + connection with Clean Start set to 1, the Server MUST set Session Present to + 0 in the CONNACK packet in addition to setting a 0x00 (Success) Reason Code + in the CONNACK packet.

+
+

[MQTT-3.2.2-3]

+
+

If the Server accepts a + connection with Clean Start set to 0 and the Server has Session State for the + ClientID, it MUST set Session Present to 1 in the CONNACK packet, otherwise + it MUST set Session Present to 0 in the CONNACK packet. In both cases it MUST + set a 0x00 (Success) Reason Code in the CONNACK packet.

+
+

[MQTT-3.2.2-4]

+
+

If the Client does not have + Session State and receives Session Present set to 1 it MUST close the Network + Connection.

+
+

[MQTT-3.2.2-5]

+
+

If the Client does have Session + State and receives Session Present set to 0 it MUST discard its Session State + if it continues with the Network Connection.

+
+

[MQTT-3.2.2-6]

+
+

If a Server sends a CONNACK + packet containing a non-zero Reason Code it MUST set Session Present to 0.

+
+

[MQTT-3.2.2-7]

+
+

If a Server sends a CONNACK + packet containing a Reason code of 0x80 or greater it MUST then close the + Network Connection.

+
+

[MQTT-3.2.2-8]

+
+

The Server sending the CONNACK + packet MUST use one of the Connect Reason Code values.

+
+

[MQTT-3.2.2-9]

+
+

If a Server does not support QoS + 1 or QoS 2 PUBLISH packets it MUST send a Maximum QoS in the CONNACK packet + specifying the highest QoS it supports.

+
+

[MQTT-3.2.2-10]

+
+

A Server that does not support + QoS 1 or QoS 2 PUBLISH packets MUST still accept SUBSCRIBE packets containing + a Requested QoS of 0, 1 or 2.

+
+

[MQTT-3.2.2-11]

+
+

If a Client receives a Maximum + QoS from a Server, it MUST NOT send PUBLISH packets at a QoS level exceeding + the Maximum QoS level specified.

+
+

[MQTT-3.2.2-12]

+
+

If a Server receives a CONNECT + packet containing a Will QoS that exceeds its capabilities, it MUST reject + the connection. It SHOULD use a CONNACK packet with Reason Code 0x9B (QoS not + supported) as described in section 4.13 Handling errors, and MUST close the Network + Connection.

+
+

[MQTT-3.2.2-13]

+
+

If a Server receives a CONNECT + packet containing a Will Message with the Will Retain 1, and it does not + support retained messages, the Server MUST reject the connection request. It + SHOULD send CONNACK with Reason Code 0x9A (Retain not supported) and then it + MUST close the Network Connection.

+
+

[MQTT-3.2.2-14]

+
+

A Client receiving Retain Available + set to 0 from the Server MUST NOT send a PUBLISH packet with the RETAIN flag + set to 1.

+
+

[MQTT-3.2.2-15]

+
+

The Client MUST NOT send packets + exceeding Maximum Packet Size to the Server.

+
+

[MQTT-3.2.2-16]

+
+

If the Client connects using a + zero length Client Identifier, the Server MUST respond with a CONNACK + containing an Assigned Client Identifier. The Assigned Client Identifier MUST + be a new Client Identifier not used by any other Session currently in the + Server.

+
+

[MQTT-3.2.2-17]

+
+

The Client MUST NOT send a Topic + Alias in a PUBLISH packet to the Server greater than this value.

+
+

[MQTT-3.2.2-18]

+
+

Topic Alias Maximum is absent, + the Client MUST NOT send any Topic Aliases on to the Server.

+
+

[MQTT-3.2.2-19]

+
+

The Server MUST NOT send this + property if it would increase the size of the CONNACK packet beyond the + Maximum Packet Size specified by the Client.

+
+

[MQTT-3.2.2-20]

+
+

The Server MUST NOT send this + property if it would increase the size of the CONNACK packet beyond the + Maximum Packet Size specified by the Client.

+
+

[MQTT-3.2.2-21]

+
+

If the Server sends a Server + Keep Alive on the CONNACK packet, the Client MUST use this value instead of + the Keep Alive value the Client sent on CONNECT.

+
+

[MQTT-3.2.2-22]

+
+

If the Server does not send the + Server Keep Alive, the Server MUST use the Keep Alive value set by the Client + on CONNECT.

+
+

[MQTT-3.3.1-1]

+
+

The DUP flag MUST be set to 1 by + the Client or Server when it attempts to re-deliver a PUBLISH packet.

+
+

[MQTT-3.3.1-2]

+
+

The DUP flag MUST be set to 0 + for all QoS 0 messages.

+
+

[MQTT-3.3.1-3]

+
+

The DUP flag in the outgoing + PUBLISH packet is set independently to the incoming PUBLISH packet, its value + MUST be determined solely by whether the outgoing PUBLISH packet is a + retransmission.

+
+

[MQTT-3.3.1-4]

+
+

A PUBLISH Packet MUST NOT have + both QoS bits set to 1.

+
+

[MQTT-3.3.1-5]

+
+

If the RETAIN flag is set to 1 + in a PUBLISH packet sent by a Client to a Server, the Server MUST replace any + existing retained message for this topic and store the Application Message.

+
+

[MQTT-3.3.1-6]

+
+

If the Payload contains zero bytes + it is processed normally by the Server but any retained message with the same + topic name MUST be removed and any future subscribers for the topic will not + receive a retained message.

+
+

[MQTT-3.3.1-7]

+
+

A retained message with a + Payload containing zero bytes MUST NOT be stored as a retained message on the + Server.

+
+

[MQTT-3.3.1-8]

+
+

If the RETAIN flag is 0 in a + PUBLISH packet sent by a Client to a Server, the Server MUST NOT store the + message as a retained message and MUST NOT remove or replace any existing retained + message.

+
+

[MQTT-3.3.1-9]

+
+

If Retain Handling is set to 0 the Server MUST send the + retained messages matching the Topic Filter of the subscription to the Client.

+
+

[MQTT-3.3.1-10]

+
+

If Retain Handling is set to 1 then + if the subscription did already exist, the Server MUST send all retained + message matching the Topic Filter of the subscription to the Client, and if + the subscription did not exist, the Server MUST NOT send the retained + messages.

+
+

[MQTT-3.3.1-11]

+
+

If Retain Handling is set to 2, + the Server MUST NOT send the retained

+
+

[MQTT-3.3.1-12]

+
+

If the value of Retain As Published + subscription option is set to 0, the Server MUST set the RETAIN flag to 0 + when forwarding an Application Message regardless of how the RETAIN flag was + set in the received PUBLISH packet.

+
+

[MQTT-3.3.1-13]

+
+

If the value of Retain As + Published subscription option is set to 1, the Server MUST set the RETAIN + flag equal to the RETAIN flag in the received PUBLISH packet.

+
+

[MQTT-3.3.2-1]

+
+

The Topic Name MUST be present + as the first field in the PUBLISH packet Variable Header. It MUST be a UTF-8 + Encoded String.

+
+

[MQTT-3.3.2-2]

+
+

The Topic Name in the PUBLISH + packet MUST NOT contain wildcard characters.

+
+

[MQTT-3.3.2-3]

+
+

The Topic Name in a PUBLISH + packet sent by a Server to a subscribing Client MUST match the Subscription’s + Topic Filter.

+
+

[MQTT-3.3.2-4]

+
+

A Server MUST send the Payload + Format Indicator unaltered to all subscribers receiving the message.

+
+

[MQTT-3.3.2-5]

+
+

If the Message Expiry Interval + has passed and the Server has not managed to start onward delivery to a + matching subscriber, then it MUST delete the copy of the message for that + subscriber.

+
+

[MQTT-3.3.2-6]

+
+

The PUBLISH packet sent to a + Client by the Server MUST contain a Message Expiry Interval set to the + received value minus the time that the message has been waiting in the + Server.

+
+

[MQTT-3.3.2-7]

+
+

A receiver MUST NOT carry + forward any Topic Alias mappings from one Network Connection to another.

+
+

[MQTT-3.3.2-8]

+
+

A sender MUST NOT send a PUBLISH + packet containing a Topic Alias which has the value 0.

+
+

[MQTT-3.3.2-9]

+
+

A Client MUST NOT send a PUBLISH + packet with a Topic Alias greater than the Topic Alias Maximum value returned + by the Server in the CONNACK packet.

+
+

[MQTT-3.3.2-10]

+
+

A Client MUST accept all Topic + Alias values greater than 0 and less than or equal to the Topic Alias Maximum + value that it sent in the CONNECT packet.

+
+

[MQTT-3.3.2-11]

+
+

A Server MUST NOT send a PUBLISH + packet with a Topic Alias greater than the Topic Alias Maximum value sent by + the Client in the CONNECT packet.

+
+

[MQTT-3.3.2-12]

+
+

A Server MUST accept all Topic + Alias values greater than 0 and less than or equal to the Topic Alias Maximum + value that it returned in the CONNACK packet.

+
+

[MQTT-3.3.2-13]

+
+

The Response Topic MUST be a + UTF-8 Encoded String.

+
+

[MQTT-3.3.2-14]

+
+

The Response Topic MUST NOT + contain wildcard characters.

+
+

[MQTT-3.3.2-15]

+
+

The Server MUST send the + Response Topic unaltered to all subscribers receiving the Application Message.

+
+

[MQTT-3.3.2-16]

+
+

The Server MUST send the + Correlation Data unaltered to all subscribers receiving the Application + Message.

+
+

[MQTT-3.3.2-17]

+
+

The Server MUST send all User + Properties unaltered in a PUBLISH packet when forwarding the Application + Message to a Client.

+
+

[MQTT-3.3.2-18]

+
+

The Server MUST maintain the + order of User Properties when forwarding the Application Message.

+
+

[MQTT-3.3.2-19]

+
+

The Content Type MUST be a UTF-8 + Encoded String.

+
+

[MQTT-3.3.2-20]

+
+

A Server MUST send the Content + Type unaltered to all subscribers receiving the Application Message.

+
+

[MQTT-3.3.4-1]

+
+

The receiver of a PUBLISH Packet + MUST respond with the packet as determined by the QoS in the PUBLISH Packet.

+
+

[MQTT-3.3.4-2]

+
+

In this case the Server MUST + deliver the message to the Client respecting the maximum QoS of all the + matching subscriptions.

+
+

[MQTT-3.3.4-3]

+
+

If the Client specified a + Subscription Identifier for any of the overlapping subscriptions the Server + MUST send those Subscription Identifiers in the message which is published as + the result of the subscriptions.

+
+

[MQTT-3.3.4-4]

+
+

If the Server sends a single + copy of the message it MUST include in the PUBLISH packet the Subscription + Identifiers for all matching subscriptions which have a Subscription + Identifiers, their order is not significant.

+
+

[MQTT-3.3.4-5]

+
+

If the Server sends multiple + PUBLISH packets it MUST send, in each of them, the Subscription Identifier of + the matching subscription if it has a Subscription Identifier.

+
+

[MQTT-3.3.4-6]

+
+

A PUBLISH packet sent from a + Client to a Server MUST NOT contain a Subscription Identifier.

+
+

[MQTT-3.3.4-7]

+
+

The Client MUST NOT send more + than Receive Maximum QoS 1 and QoS 2 PUBLISH packets for which it has not + received PUBACK, PUBCOMP, or PUBREC with a Reason Code of 128 or greater from + the Server.

+
+

[MQTT-3.3.4-8]

+
+

The Client MUST NOT delay the + sending of any packets other than PUBLISH packets due to having sent Receive + Maximum PUBLISH packets without receiving acknowledgements for them.

+
+

[MQTT-3.3.4-9]

+
+

The Server MUST NOT send more + than Receive Maximum QoS 1 and QoS 2 PUBLISH packets for which it has not + received PUBACK, PUBCOMP, or PUBREC with a Reason Code of 128 or greater from + the Client.

+
+

[MQTT-3.3.4-10]

+
+

The Server MUST NOT delay the sending of any packets other + than PUBLISH packets due to having sent Receive Maximum PUBLISH packets + without receiving acknowledgements for them.

+
+

[MQTT-3.4.2-1]

+
+

The Client or Server sending the + PUBACK packet MUST use one of the PUBACK Reason Codes.

+
+

[MQTT-3.4.2-2]

+
+

The sender MUST NOT send this + property if it would increase the size of the PUBACK packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.4.2-3]

+
+

The sender MUST NOT send this + property if it would increase the size of the PUBACK packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.5.2-1]

+
+

The Client or Server sending the + PUBREC packet MUST use one of the PUBREC Reason Codes.

+
+

[MQTT-3.5.2-2]

+
+

The sender MUST NOT send this property + if it would increase the size of the PUBREC packet beyond the Maximum Packet + Size specified by the receiver.

+
+

[MQTT-3.5.2-3]

+
+

The sender MUST NOT send this + property if it would increase the size of the PUBREC packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.6.1-1]

+
+

Bits 3,2,1 and 0 of the Fixed + Header in the PUBREL packet are reserved and MUST be set to 0,0,1 and 0 + respectively. The Server MUST treat any other value as malformed and close + the Network Connection.

+
+

[MQTT-3.6.2-1]

+
+

The Client or Server sending the + PUBREL packet MUST use one of the PUBREL Reason Codes.

+
+

[MQTT-3.6.2-2]

+
+

The sender MUST NOT send this + Property if it would increase the size of the PUBREL packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.6.2-3]

+
+

The sender MUST NOT send this + property if it would increase the size of the PUBREL packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.7.2-1]

+
+

The Client or Server sending the + PUBCOMP packets MUST use one of the PUBCOMP Reason Codes.

+
+

[MQTT-3.7.2-2]

+
+

The sender MUST NOT use this + Property if it would increase the size of the PUBCOMP packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.7.2-3]

+
+

The sender MUST NOT send this + property if it would increase the size of the PUBCOMP packet beyond the + Maximum Packet Size specified by receiver.

+
+

[MQTT-3.8.1-1]

+
+

Bits 3,2,1 and 0 of the Fixed + Header of the SUBSCRIBE packet are reserved and MUST be set to 0,0,1 and 0 + respectively. The Server MUST treat any other value as malformed and close + the Network Connection

+
+

[MQTT-3.8.3-1]

+
+

The Topic Filters MUST be a + UTF-8 Encoded String.

+
+

[MQTT-3.8.3-2]

+
+

The Payload MUST contain at + least one Topic Filter and Subscription Options pair.

+
+

[MQTT-3.8.3-3]

+
+

Bit 2 of the Subscription Options + represents the No Local option. If the value is 1, Application Messages MUST + NOT be forwarded to a connection with a ClientID equal to the ClientID of the + publishing connection.

+
+

[MQTT-3.8.3-4]

+
+

It is a Protocol Error to set + the No Local bit to 1 on a Shared Subscription.

+
+

[MQTT-3.8.3-5]

+
+

The Server MUST treat a + SUBSCRIBE packet as malformed if any of Reserved bits in the Payload are + non-zero.

+
+

[MQTT-3.8.4-1]

+
+

When the Server receives a SUBSCRIBE + packet from a Client, the Server MUST respond with a SUBACK packet.

+
+

[MQTT-3.8.4-2]

+
+

The SUBACK packet MUST have the + same Packet Identifier as the SUBSCRIBE packet that it is acknowledging.

+
+

[MQTT-3.8.4-3]

+
+

If a Server receives a SUBSCRIBE + packet containing a Topic Filter that is identical to a Non‑shared + Subscription’s Topic Filter for the current Session then it MUST replace that + existing Subscription with a new Subscription.

+
+

[MQTT-3.8.4-4]

+
+

If the Retain Handling option is + 0, any existing retained messages matching the Topic Filter MUST be re-sent, but + Application Messages MUST NOT be lost due to replacing the Subscription.

+
+

[MQTT-3.8.4-5]

+
+

If a Server receives a SUBSCRIBE + packet that contains multiple Topic Filters it MUST handle that packet as if it + had received a sequence of multiple SUBSCRIBE packets, except that it + combines their responses into a single SUBACK response.

+
+

[MQTT-3.8.4-6]

+
+

The SUBACK packet sent by the + Server to the Client MUST contain a Reason Code for each Topic + Filter/Subscription Option pair.

+
+

[MQTT-3.8.4-7]

+
+

This Reason Code MUST either + show the maximum QoS that was granted for that Subscription or indicate that + the subscription failed.

+
+

[MQTT-3.8.4-8]

+
+

The QoS of Payload Messages sent + in response to a Subscription MUST be the minimum of the QoS of the + originally published message and the Maximum QoS granted by the Server.

+
+

[MQTT-3.9.2-1]

+
+

The Server MUST NOT send this + Property if it would increase the size of the SUBACK packet beyond the + Maximum Packet Size specified by the Client.

+
+

[MQTT-3.9.2-2]

+
+

The Server MUST NOT send this + property if it would increase the size of the SUBACK packet beyond the + Maximum Packet Size specified by the Client.

+
+

[MQTT-3.9.3-1]

+
+

The order of Reason Codes in the + SUBACK packet MUST match the order of Topic Filters in the SUBSCRIBE packet.

+
+

[MQTT-3.9.3-2]

+
+

The Server sending the SUBACK + packet MUST send one of the Subscribe Reason Code values for each Topic + Filter received.

+
+

[MQTT-3.10.1-1]

+
+

Bits 3,2,1 and 0 of the Fixed + Header of the UNSUBSCRIBE packet are reserved and MUST be set to 0,0,1 and 0 + respectively. The Server MUST treat any other value as malformed and close + the Network Connection

+
+

[MQTT-3.10.3-1]

+
+

The Topic Filters in an + UNSUBSCRIBE packet MUST be UTF-8 Encoded Strings.

+
+

[MQTT-3.10.3-2]

+
+

The Payload of an UNSUBSCRIBE + packet MUST contain at least one Topic Filter.

+
+

[MQTT-3.10.4-1]

+
+

The Topic Filters (whether they + contain wildcards or not) supplied in an UNSUBSCRIBE packet MUST be compared + character-by-character with the current set of Topic Filters held by the + Server for the Client. If any filter matches exactly then its owning + Subscription MUST be deleted.

+
+

[MQTT-3.10.4-2]

+
+

When a Server receives + UNSUBSCRIBE It MUST stop adding any new messages which match the Topic + Filters, for delivery to the Client.

+
+

[MQTT-3.10.4-3]

+
+

When a Server receives + UNSUBSCRIBE It MUST complete the delivery of any QoS 1 or QoS 2 messages + which match the Topic Filters and it has started to send to the Client.

+
+

[MQTT-3.10.4-4]

+
+

The Server MUST respond to an + UNSUBSCRIBE request by sending an UNSUBACK packet.

+
+

[MQTT-3.10.4-5]

+
+

The UNSUBACK packet MUST have + the same Packet Identifier as the UNSUBSCRIBE packet. Even where no Topic + Subscriptions are deleted, the Server MUST respond with an UNSUBACK.

+
+

[MQTT-3.10.4-6]

+
+

If a Server receives an UNSUBSCRIBE + packet that contains multiple Topic Filters, it MUST process that packet as + if it had received a sequence of multiple UNSUBSCRIBE packets, except that it + sends just one UNSUBACK response.

+
+

[MQTT-3.11.2-1]

+
+

The Server MUST NOT send this + Property if it would increase the size of the UNSUBACK packet beyond the + Maximum Packet Size specified by the Client.

+
+

[MQTT-3.11.2-2]

+
+

The Server MUST NOT send this + property if it would increase the size of the UNSUBACK packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.11.3-1]

+
+

The order of Reason Codes in the + UNSUBACK packet MUST match the order of Topic Filters in the UNSUBSCRIBE + packet.

+
+

[MQTT-3.11.3-2]

+
+

The Server sending the UNSUBACK + packet MUST use one of the UNSUBSCRIBE Reason Code values for each Topic + Filter received.

+
+

[MQTT-3.12.4-1]

+
+

The Server MUST send a PINGRESP + packet in response to a PINGREQ packet.

+
+

[MQTT-3.14.0-1]

+
+

A Server MUST NOT send a + DISCONNECT until after it has sent a CONNACK with Reason Code of less than + 0x80.

+
+

[MQTT-3.14.1-1]

+
+

The Client or Server MUST + validate that reserved bits are set to 0. If they are not zero it sends a + DISCONNECT packet with a Reason code of 0x81 (Malformed Packet).

+
+

[MQTT-3.14.2-1]

+
+

The Client or Server sending the + DISCONNECT packet MUST use one of the DISCONNECT Reason Codes.

+
+

[MQTT-3.14.2-2]

+
+

The Session Expiry Interval MUST + NOT be sent on a DISCONNECT by the Server.

+
+

[MQTT-3.14.2-3]

+
+

The sender MUST NOT use this + Property if it would increase the size of the DISCONNECT packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.14.2-4]

+
+

The sender MUST NOT send this + property if it would increase the size of the DISCONNECT packet beyond the + Maximum Packet Size specified by the receiver.

+
+

[MQTT-3.14.4-1]

+
+

After sending a DISCONNECT + packet the sender MUST NOT send any more MQTT Control Packets on that Network + Connection.

+
+

[MQTT-3.14.4-2]

+
+

After sending a DISCONNECT + packet the sender MUST close the Network Connection.

+
+

[MQTT-3.14.4-3]

+
+

On receipt of DISCONNECT with a + Reason Code of 0x00 (Success) the Server MUST discard any Will Message + associated with the current Connection without publishing it.

+
+

[MQTT-3.15.1-1]

+
+

Bits 3,2,1 and 0 of the Fixed + Header of the AUTH packet are reserved and MUST all be set to 0. The Client + or Server MUST treat any other value as malformed and close the Network + Connection.

+
+

[MQTT-3.15.2-1]

+
+

The sender of the AUTH Packet + MUST use one of the Authenticate Reason Codes.

+
+

[MQTT-3.15.2-2]

+
+

The sender MUST NOT send this property if it would + increase the size of the AUTH packet beyond the Maximum Packet Size specified + by the receiver

+
+

[MQTT-3.15.2-3]

+
+

The sender MUST NOT send this + property if it would increase the size of the AUTH packet beyond the Maximum + Packet Size specified by the receiver.

+
+

[MQTT-4.1.0-1]

+
+

The Client and Server MUST NOT + discard the Session State while the Network Connection is open.

+
+

[MQTT-4.2.0-1]

+
+

A Client or Server MUST support + the use of one or more underlying transport protocols that provide an + ordered, lossless, stream of bytes from the Client to Server and Server to + Client.

+
+

[MQTT-4.1.0-2]

+
+

The Server MUST discard the + Session State when the Network Connection is closed and the Session Expiry + Interval has passed.

+
+

[MQTT-4.3.1-1]

+
+

In the QoS 0 delivery protocol, + the sender MUST send a PUBLISH packet with QoS 0 and DUP flag set to 0.

+
+

[MQTT-4.3.2-1]

+
+

In the QoS 1 delivery protocol, + the sender MUST assign an unused Packet Identifier each time it has a new + Application Message to publish.

+
+

[MQTT-4.3.2-2]

+
+

In the QoS 1 delivery protocol, + the sender MUST send a PUBLISH packet containing this Packet Identifier with + QoS 1 and DUP flag set to 0.

+
+

[MQTT-4.3.2-3]

+
+

In the QoS 1 delivery protocol, + the sender MUST treat the PUBLISH packet as “unacknowledged” until it has + received the corresponding PUBACK packet from the receiver.

+
+

[MQTT-4.3.2-4]

+
+

In the QoS 1 delivery protocol, + the receiver MUST respond with a PUBACK packet containing the Packet + Identifier from the incoming PUBLISH packet, having accepted ownership of the + Application Message.

+
+

[MQTT-4.3.2-5]

+
+

In the QoS 1 delivery protocol, + the receiver after it has sent a PUBACK packet the receiver MUST treat any + incoming PUBLISH packet that contains the same Packet Identifier as being a + new Application Message, irrespective of the setting of its DUP flag.

+
+

[MQTT-4.3.3-1]

+
+

In the QoS 2 delivery protocol, + the sender MUST assign an unused Packet Identifier when it has a new + Application Message to publish.

+
+

[MQTT-4.3.3-2]

+
+

In the QoS 2 delivery protocol, + the sender MUST send a PUBLISH packet containing this Packet Identifier with + QoS 2 and DUP flag set to 0.

+
+

[MQTT-4.3.3-3]

+
+

In the QoS 2 delivery protocol, + the sender MUST treat the PUBLISH packet as “unacknowledged” until it has + received the corresponding PUBREC packet from the receiver.

+
+

[MQTT-4.3.3-4]

+
+

In the QoS 2 delivery protocol, + the sender MUST send a PUBREL packet when it receives a PUBREC packet from the + receiver with a Reason Code value less than 0x80. This PUBREL packet MUST + contain the same Packet Identifier as the original PUBLISH packet.

+
+

[MQTT-4.3.3-5]

+
+

In the QoS 2 delivery protocol, + the sender MUST treat the PUBREL packet as “unacknowledged” until it has + received the corresponding PUBCOMP packet from the receiver.

+
+

[MQTT-4.3.3-6]

+
+

In the QoS 2 delivery protocol, + the sender MUST NOT re-send the PUBLISH once it has sent the corresponding + PUBREL packet.

+
+

[MQTT-4.3.3-7]

+
+

In the QoS 2 delivery protocol, + the sender MUST NOT apply Application Message expiry if a PUBLISH packet has + been sent.

+
+

[MQTT-4.3.3-8]

+
+

In the QoS 2 delivery protocol, + the receiver MUST respond with a PUBREC containing the Packet Identifier from + the incoming PUBLISH packet, having accepted ownership of the Application + Message.

+
+

[MQTT-4.3.3-9]

+
+

In the QoS 2 delivery protocol, + the receiver if it has sent a PUBREC with a Reason Code of 0x80 or greater, + the receiver MUST treat any subsequent PUBLISH packet that contains that + Packet Identifier as being a new Application Message.

+
+

[MQTT-4.3.3-10]

+
+

In the QoS 2 delivery protocol, + the receiver until it has received the corresponding PUBREL packet, the + receiver MUST acknowledge any subsequent PUBLISH packet with the same Packet + Identifier by sending a PUBREC. It MUST NOT cause duplicate messages to be + delivered to any onward recipients in this case.

+
+

[MQTT-4.3.3-11]

+
+

In the QoS 2 delivery protocol, + the receiver MUST respond to a PUBREL packet by sending a PUBCOMP packet + containing the same Packet Identifier as the PUBREL.

+
+

[MQTT-4.3.3-12]

+
+

In the QoS 2 delivery protocol, + the receiver After it has sent a PUBCOMP, the receiver MUST treat any + subsequent PUBLISH packet that contains that Packet Identifier as being a new + Application Message.

+
+

[MQTT-4.3.3-13]

+
+

In the QoS 2 delivery protocol, + the receiver MUST continue the QoS 2 acknowledgement sequence even if + it has applied Application Message expiry.

+
+

[MQTT-4.4.0-1]

+
+

When a Client reconnects with + Clean Start set to 0 and a session is present, both the Client and Server + MUST resend any unacknowledged PUBLISH packets (where QoS > 0) and PUBREL + packets using their original Packet Identifiers. This is the only + circumstance where a Client or Server is REQUIRED to resend messages. Clients + and Servers MUST NOT resend messages at any other time.

+
+

[MQTT-4.4.0-2]

+
+

If PUBACK or PUBREC is received + containing a Reason Code of 0x80 or greater the corresponding PUBLISH packet + is treated as acknowledged, and MUST NOT be retransmitted.

+
+

[MQTT-4.5.0-1]

+
+

When a Server takes ownership of + an incoming Application Message it MUST add it to the Session State for those + Clients that have matching Subscriptions.

+
+

[MQTT-4.5.0-2]

+
+

The Client MUST acknowledge any + Publish packet it receives according to the applicable QoS rules regardless + of whether it elects to process the Application Message that it contains.

+
+

[MQTT-4.6.0-1]

+
+

When the Client re-sends any + PUBLISH packets, it MUST re-send them in the order in which the original PUBLISH + packets were sent (this applies to QoS 1 and QoS 2 messages).

+
+

[MQTT-4.6.0-2]

+
+

The Client MUST send PUBACK + packets in the order in which the corresponding PUBLISH packets were received + (QoS 1 messages).

+
+

[MQTT-4.6.0-3]

+
+

The Client MUST send PUBREC packets + in the order in which the corresponding PUBLISH packets were received (QoS 2 + messages).

+
+

[MQTT-4.6.0-4]

+
+

The Client MUST send PUBREL + packets in the order in which the corresponding PUBREC packets were received + (QoS 2 messages).

+
+

[MQTT-4.6.0-5]

+
+

When a Server processes a message + that has been published to an Ordered Topic, it MUST send PUBLISH packets to + consumers (for the same Topic and QoS) in the order that they were received + from any given Client.

+
+

[MQTT-4.6.0-6]

+
+

A Server MUST treat every, Topic + as an Ordered Topic when it is forwarding messages on Non‑shared + Subscriptions.

+
+

[MQTT-4.7.0-1]

+
+

The wildcard characters can be + used in Topic Filters, but MUST NOT be used within a Topic Name.

+
+

[MQTT-4.7.1-1]

+
+

The multi-level wildcard + character MUST be specified either on its own or following a topic level + separator. In either case it MUST be the last character specified in the + Topic Filter.

+
+

[MQTT-4.7.1-2]

+
+

The single-level wildcard can be + used at any level in the Topic Filter, including first and last levels. Where + it is used, it MUST occupy an entire level of the filter.

+
+

[MQTT-4.7.2-1]

+
+

The Server MUST NOT match Topic + Filters starting with a wildcard character (# or +) with Topic Names + beginning with a $ character.

+
+

[MQTT-4.7.3-1]

+
+

All Topic Names and Topic + Filters MUST be at least one character long.

+
+

[MQTT-4.7.3-2]

+
+

Topic Names and Topic Filters + MUST NOT include the null character (Unicode U+0000).

+
+

[MQTT-4.7.3-3]

+
+

Topic Names and Topic Filters + are UTF-8 Encoded Strings; they MUST NOT encode to more than 65,535 bytes.

+
+

[MQTT-4.7.3-4]

+
+

When it performs subscription + matching the Server MUST NOT perform any normalization of Topic Names or + Topic Filters, or any modification or substitution of unrecognized + characters.

+
+

[MQTT-4.8.2-1]

+
+

A Shared Subscription's Topic + Filter MUST start with $share/ and MUST contain a ShareName that is at least + one character long.

+
+

[MQTT-4.8.2-2]

+
+

The ShareName MUST NOT contain + the characters "/", "+" or "#", but MUST be + followed by a "/" character. This "/" character MUST be + followed by a Topic Filter.

+
+

[MQTT-4.8.2-3]

+
+

The Server MUST respect the + granted QoS for the Clients subscription.

+
+

[MQTT-4.8.2-4]

+
+

The Server MUST complete the + delivery of the message to that Client when it reconnects.

+
+

[MQTT-4.8.2-5]

+
+

If the Clients Session + terminates before the Client reconnects, the Server MUST NOT send the + Application Message to any other subscribed Client.

+
+

[MQTT-4.8.2-6]

+
+

If a Client responds with a + PUBACK or PUBREC containing a Reason Code of 0x80 or greater to a PUBLISH + packet from the Server, the Server MUST discard the Application Message and + not attempt to send it to any other Subscriber.

+
+

[MQTT-4.9.0-1]

+
+

The Client or Server MUST set + its initial send quota to a non-zero value not exceeding the Receive Maximum.

+
+

[MQTT-4.9.0-2]

+
+

Each time the Client or Server + sends a PUBLISH packet at QoS > 0, it decrements the send quota. If the + send quota reaches zero, the Client or Server MUST NOT send any more PUBLISH + packets with QoS > 0.

+
+

[MQTT-4.9.0-3]

+
+

The Client and Server MUST + continue to process and respond to all other MQTT Control Packets even if the + quota is zero.

+
+

[MQTT-4.12.0-1]

+
+

If the Server does not support + the Authentication Method supplied by the Client, it MAY send a CONNACK with + a Reason Code of 0x8C (Bad authentication method) or 0x87 (Not Authorized) as + described in section 4.13 and MUST close the Network Connection.

+
+

[MQTT-4.12.0-2]

+
+

If the Server requires + additional information to complete the authorization, it can send an AUTH + packet to the Client. This packet MUST contain a Reason Code of 0x18 (Continue + authentication).

+
+

[MQTT-4.12.0-3]

+
+

The Client responds to an AUTH packet + from the Server by sending a further AUTH packet. This packet MUST contain a + Reason Code of 0x18 (Continue authentication).

+
+

[MQTT-4.12.0-4]

+
+

The Server can reject the + authentication at any point in this process. It MAY send a CONNACK with a + Reason Code of 0x80 or above as described in section 4.13, and MUST close the + Network Connection.

+
+

[MQTT-4.12.0-5]

+
+

If the initial CONNECT packet included + an Authentication Method property then all AUTH packets, and any successful + CONNACK packet MUST include an Authentication Method Property with the same + value as in the CONNECT packet.

+
+

[MQTT-4.12.0-6]

+
+

If the Client does not include + an Authentication Method in the CONNECT, the Server MUST NOT send an AUTH + packet, and it MUST NOT send an Authentication Method in the CONNACK packet.

+
+

[MQTT-4.12.0-7]

+
+

If the Client does not include + an Authentication Method in the CONNECT, the Client MUST NOT send an AUTH + packet to the Server.

+
+

[MQTT-4.12.1-1]

+
+

If the Client supplied an + Authentication Method in the CONNECT packet it can initiate a + re-authentication at any time after receiving a CONNACK. It does this by + sending an AUTH packet with a Reason Code of 0x19 (Re-authentication). The + Client MUST set the Authentication Method to the same value as the + Authentication Method originally used to authenticate the Network Connection.

+
+

[MQTT-4.12.1-2]

+
+

If the re-authentication fails, + the Client or Server SHOULD send DISCONNECT with an appropriate Reason Code + and MUST close the Network Connection.

+
+

[MQTT-4.13.1-1]

+
+

When a Server detects a Malformed + Packet or Protocol Error, and a Reason Code is given in the specification, it + MUST close the Network Connection.

+
+

[MQTT-4.13.2-1]

+
+

The CONNACK and DISCONNECT + packets allow a Reason Code of 0x80 or greater to indicate that the Network + Connection will be closed. If a Reason Code of 0x80 or greater is specified, + then the Network Connection MUST be closed whether or not the CONNACK or DISCONNECT + is sent.

+
+

[MQTT-6.0.0-1]

+
+

MQTT Control Packets MUST be + sent in WebSocket binary data frames. If any other type of data frame is + received the recipient MUST close the Network Connection.

+
+

[MQTT-6.0.0-2]

+
+

A single WebSocket data frame + can contain multiple or partial MQTT Control Packets. The receiver MUST NOT + assume that MQTT Control Packets are aligned on WebSocket frame boundaries.

+
+

[MQTT-6.0.0-3]

+
+

The Client MUST include “mqtt” + in the list of WebSocket Sub Protocols it offers.

+
+

[MQTT-6.0.0-4]

+
+

The WebSocket Subprotocol name + selected and returned by the Server MUST be “mqtt”.

+
+ +

 

+ +
+ +

Appendix C. Summary of new +features in MQTT v5.0 (non-normative)

+ +
+ +

The following new features are added to MQTT v5.0

+ +

 

+ +

·         +Session expiry

+ +

Split the Clean Session flag into a Clean Start flag which +indicates that the session should start without using an existing session, and +a Session Expiry interval which says how long to retain the session after a +disconnect. The session expiry interval can be modified at disconnect. Setting +of Clean Start to 1 and Session Expiry Interval to 0 is equivalent in MQTT v3.1.1 +of setting Clean Session to 1.

+ +

 

+ +

·         +Message expiry

+ +

Allow an expiry interval to be set when a message is +published.

+ +

 

+ +

·         +Reason code on all ACKs

+ +

Change all response packets to contain a reason code. This +include CONNACK, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBACK, UNSUBACK, DISCONNECT, +and AUTH. This allows the invoker to determine whether the requested function +succeeded.

+ +

 

+ +

·         +Reason string on all ACKs

+ +

Change most packets with a reason code to also allow an +optional reason string. This is designed for problem determination and is not +intended to be parsed by the receiver.

+ +

 

+ +

·         +Server disconnect

+ +

Allow DISCONNECT to be sent by the Server to indicate the +reason the connection is closed.

+ +

 

+ +

·         +Payload format and content type

+ +

Allow the payload format (binary, text) and a MIME style +content type to be specified when a message is published. These are forwarded +on to the receiver of the message.

+ +

 

+ +

·         +Request / Response

+ +

Formalize the request/response pattern within MQTT and +provide the Response Topic and Correlation Data properties to allow response +messages to be routed back to the publisher of a request. Also, add the ability +for the Client to get configuration information from the Server about how to +construct the response topics.

+ +

 

+ +

·         +Shared Subscriptions

+ +

Add shared subscription support allowing for load balanced +consumers of a subscription

+ +

 

+ +

·         +Subscription ID

+ +

Allow a numeric subscription identifier to be specified on +a SUBSCRIBE, and returned on the message when it is delivered. This allows the +Client to determine which subscription or subscriptions caused the message to +be delivered.

+ +

 

+ +

·         +Topic Alias

+ +

Decrease the size of the MQTT packet overhead by allowing +the topic name to be abbreviated to a small integer. The Client and Server +independently specify how many topic aliases they allow.

+ +

 

+ +

·         +Flow control

+ +

Allow the Client and Server to independently specify the +number of outstanding reliable messages (QoS>0) they allow. The sender pauses +sending such messages to stay below this quota. This is used to limit the rate +of reliable messages, and to limit how many are in flight at one time.

+ +

 

+ +

·         +User properties

+ +

Add User Properties to most packets. User properties on +PUBLISH are included with the message and are defined by the Client +applications. The user properties on PUBLISH and Will Properties are forwarded +by the Server to the receiver of the message. User +properties on the CONNECT, SUBSCRIBE, and UNSUBSCRIBE packets are defined by +the Server implementation. The user properties on CONNACK PUBACK, PUBREC, +PUBREL, PUBCOMP, SUBACK, UNSUBACK and AUTH packets are defined by the sender, +and are unique to the sender implementation. The meaning of user properties is +not defined by MQTT.

+ +

 

+ +

·         +Maximum Packet Size

+ +

Allow the Client and Server to independently specify the +maximum packet size they support. It is an error for the session partner to +send a larger packet.

+ +

 

+ +

·         +Optional Server feature availability

+ +

Define a set of features which the Server does not allow +and provide a mechanism for the Server to specify this to the Client. The +features which can be specified in this way are: Maximum QoS, Retain Available, +Wildcard Subscription Available, Subscription Identifier Available, and Shared +Subscription Available. It is an error for the Client to use features that the +Server has declared are not available.

+ +

 

+ +

It is possible in earlier versions of MQTT for a Server to +not implement a feature by declaring that the Client is not authorized for that +function. This feature allows such optional behavior to be declared and adds +specific Reason Codes when the Client uses one of these features anyway.

+ +

 

+ +

·         +Enhanced authentication

+ +

Provide a mechanism to enable challenge/response style authentication +including mutual authentication. This allows SASL style authentication to be +used if supported by both Client and Server, and includes the ability for a +Client to re-authenticate within a connection.

+ +

 

+ +

·         +Subscription options

+ +

Provide subscription options primarily defined to allow for +message bridge applications. These include an option to not send messages +originating on this Client (noLocal), and options for handling retained +messages on subscribe.

+ +

 

+ +

·         +Will delay

+ +

Add the ability to specify a delay between the end of the +connection and sending the will message. This is designed so that if a +connection to the session is re-established then the will message is not sent. +This allows for brief interruptions of the connection without notification to +others.

+ +

 

+ +

·         +Server Keep Alive

+ +

Allow the Server to specify the value it wishes the Client +to use as a keep alive. This allows the Server to set a maximum allowed +keepalive and still have the Client honor it.

+ +

 

+ +

·         +Assigned ClientID

+ +

In cases where the ClientID is assigned by the Server, +return the assigned ClientID. This also lifts the restriction that Server +assigned ClientIDs can only be used with Clean Session=1 connections.

+ +

 

+ +

·         +Server reference

+ +

Allow +the Server to specify an alternate Server to use on CONNACK or DISCONNECT. This +can be used as a redirect or to do provisioning.

+ +

 

+ +
+ + + + + \ No newline at end of file diff --git a/docs/mqtt_spec/MQTT Version 5.0_files/OASISLogo-v2.0.jpg b/docs/mqtt_spec/MQTT Version 5.0_files/OASISLogo-v2.0.jpg new file mode 100644 index 0000000..d80a88f Binary files /dev/null and b/docs/mqtt_spec/MQTT Version 5.0_files/OASISLogo-v2.0.jpg differ diff --git a/docs/mqtt_spec/MQTT Version 5.0_files/page-script.js b/docs/mqtt_spec/MQTT Version 5.0_files/page-script.js new file mode 100644 index 0000000..0f91f5e --- /dev/null +++ b/docs/mqtt_spec/MQTT Version 5.0_files/page-script.js @@ -0,0 +1,19735 @@ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 3092: +/***/ ((__unused_webpack_module, exports) => { + +"use strict"; + + +exports.byteLength = byteLength; +exports.toByteArray = toByteArray; +exports.fromByteArray = fromByteArray; +var lookup = []; +var revLookup = []; +var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; +} + +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62; +revLookup['_'.charCodeAt(0)] = 63; +function getLens(b64) { + var len = b64.length; + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4'); + } + + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('='); + if (validLen === -1) validLen = len; + var placeHoldersLen = validLen === len ? 0 : 4 - validLen % 4; + return [validLen, placeHoldersLen]; +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength(b64) { + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; + return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen; +} +function _byteLength(b64, validLen, placeHoldersLen) { + return (validLen + placeHoldersLen) * 3 / 4 - placeHoldersLen; +} +function toByteArray(b64) { + var tmp; + var lens = getLens(b64); + var validLen = lens[0]; + var placeHoldersLen = lens[1]; + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)); + var curByte = 0; + + // if there are placeholders, only get up to the last complete 4 chars + var len = placeHoldersLen > 0 ? validLen - 4 : validLen; + var i; + for (i = 0; i < len; i += 4) { + tmp = revLookup[b64.charCodeAt(i)] << 18 | revLookup[b64.charCodeAt(i + 1)] << 12 | revLookup[b64.charCodeAt(i + 2)] << 6 | revLookup[b64.charCodeAt(i + 3)]; + arr[curByte++] = tmp >> 16 & 0xFF; + arr[curByte++] = tmp >> 8 & 0xFF; + arr[curByte++] = tmp & 0xFF; + } + if (placeHoldersLen === 2) { + tmp = revLookup[b64.charCodeAt(i)] << 2 | revLookup[b64.charCodeAt(i + 1)] >> 4; + arr[curByte++] = tmp & 0xFF; + } + if (placeHoldersLen === 1) { + tmp = revLookup[b64.charCodeAt(i)] << 10 | revLookup[b64.charCodeAt(i + 1)] << 4 | revLookup[b64.charCodeAt(i + 2)] >> 2; + arr[curByte++] = tmp >> 8 & 0xFF; + arr[curByte++] = tmp & 0xFF; + } + return arr; +} +function tripletToBase64(num) { + return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; +} +function encodeChunk(uint8, start, end) { + var tmp; + var output = []; + for (var i = start; i < end; i += 3) { + tmp = (uint8[i] << 16 & 0xFF0000) + (uint8[i + 1] << 8 & 0xFF00) + (uint8[i + 2] & 0xFF); + output.push(tripletToBase64(tmp)); + } + return output.join(''); +} +function fromByteArray(uint8) { + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 + + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, i + maxChunkLength > len2 ? len2 : i + maxChunkLength)); + } + + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1]; + parts.push(lookup[tmp >> 2] + lookup[tmp << 4 & 0x3F] + '=='); + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + uint8[len - 1]; + parts.push(lookup[tmp >> 10] + lookup[tmp >> 4 & 0x3F] + lookup[tmp << 2 & 0x3F] + '='); + } + return parts.join(''); +} + +/***/ }), + +/***/ 7312: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +var __webpack_unused_export__; +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh + * @license MIT + */ +/* eslint-disable no-proto */ + + + +const base64 = __webpack_require__(3092); +const ieee754 = __webpack_require__(14709); +const customInspectSymbol = typeof Symbol === 'function' && typeof Symbol['for'] === 'function' // eslint-disable-line dot-notation +? Symbol['for']('nodejs.util.inspect.custom') // eslint-disable-line dot-notation +: null; +exports.lW = Buffer; +__webpack_unused_export__ = SlowBuffer; +exports.h2 = 50; +const K_MAX_LENGTH = 0x7fffffff; +__webpack_unused_export__ = K_MAX_LENGTH; + +/** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. + */ +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport(); +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && typeof console.error === 'function') { + console.error('This browser lacks typed array (Uint8Array) support which is required by ' + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.'); +} +function typedArraySupport() { + // Can typed array instances can be augmented? + try { + const arr = new Uint8Array(1); + const proto = { + foo: function () { + return 42; + } + }; + Object.setPrototypeOf(proto, Uint8Array.prototype); + Object.setPrototypeOf(arr, proto); + return arr.foo() === 42; + } catch (e) { + return false; + } +} +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined; + return this.buffer; + } +}); +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined; + return this.byteOffset; + } +}); +function createBuffer(length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"'); + } + // Return an augmented `Uint8Array` instance + const buf = new Uint8Array(length); + Object.setPrototypeOf(buf, Buffer.prototype); + return buf; +} + +/** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ + +function Buffer(arg, encodingOrOffset, length) { + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new TypeError('The "string" argument must be of type string. Received type number'); + } + return allocUnsafe(arg); + } + return from(arg, encodingOrOffset, length); +} +Buffer.poolSize = 8192; // not used by this implementation + +function from(value, encodingOrOffset, length) { + if (typeof value === 'string') { + return fromString(value, encodingOrOffset); + } + if (ArrayBuffer.isView(value)) { + return fromArrayView(value); + } + if (value == null) { + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + typeof value); + } + if (isInstance(value, ArrayBuffer) || value && isInstance(value.buffer, ArrayBuffer)) { + return fromArrayBuffer(value, encodingOrOffset, length); + } + if (typeof SharedArrayBuffer !== 'undefined' && (isInstance(value, SharedArrayBuffer) || value && isInstance(value.buffer, SharedArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length); + } + if (typeof value === 'number') { + throw new TypeError('The "value" argument must not be of type number. Received type number'); + } + const valueOf = value.valueOf && value.valueOf(); + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length); + } + const b = fromObject(value); + if (b) return b; + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from(value[Symbol.toPrimitive]('string'), encodingOrOffset, length); + } + throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + 'or Array-like Object. Received type ' + typeof value); +} + +/** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ +Buffer.from = function (value, encodingOrOffset, length) { + return from(value, encodingOrOffset, length); +}; + +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Object.setPrototypeOf(Buffer.prototype, Uint8Array.prototype); +Object.setPrototypeOf(Buffer, Uint8Array); +function assertSize(size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be of type number'); + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"'); + } +} +function alloc(size, fill, encoding) { + assertSize(size); + if (size <= 0) { + return createBuffer(size); + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpreted as a start offset. + return typeof encoding === 'string' ? createBuffer(size).fill(fill, encoding) : createBuffer(size).fill(fill); + } + return createBuffer(size); +} + +/** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ +Buffer.alloc = function (size, fill, encoding) { + return alloc(size, fill, encoding); +}; +function allocUnsafe(size) { + assertSize(size); + return createBuffer(size < 0 ? 0 : checked(size) | 0); +} + +/** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ +Buffer.allocUnsafe = function (size) { + return allocUnsafe(size); +}; +/** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ +Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(size); +}; +function fromString(string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8'; + } + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding); + } + const length = byteLength(string, encoding) | 0; + let buf = createBuffer(length); + const actual = buf.write(string, encoding); + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual); + } + return buf; +} +function fromArrayLike(array) { + const length = array.length < 0 ? 0 : checked(array.length) | 0; + const buf = createBuffer(length); + for (let i = 0; i < length; i += 1) { + buf[i] = array[i] & 255; + } + return buf; +} +function fromArrayView(arrayView) { + if (isInstance(arrayView, Uint8Array)) { + const copy = new Uint8Array(arrayView); + return fromArrayBuffer(copy.buffer, copy.byteOffset, copy.byteLength); + } + return fromArrayLike(arrayView); +} +function fromArrayBuffer(array, byteOffset, length) { + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('"offset" is outside of buffer bounds'); + } + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('"length" is outside of buffer bounds'); + } + let buf; + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array); + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset); + } else { + buf = new Uint8Array(array, byteOffset, length); + } + + // Return an augmented `Uint8Array` instance + Object.setPrototypeOf(buf, Buffer.prototype); + return buf; +} +function fromObject(obj) { + if (Buffer.isBuffer(obj)) { + const len = checked(obj.length) | 0; + const buf = createBuffer(len); + if (buf.length === 0) { + return buf; + } + obj.copy(buf, 0, 0, len); + return buf; + } + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0); + } + return fromArrayLike(obj); + } + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data); + } +} +function checked(length) { + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= K_MAX_LENGTH) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes'); + } + return length | 0; +} +function SlowBuffer(length) { + if (+length != length) { + // eslint-disable-line eqeqeq + length = 0; + } + return Buffer.alloc(+length); +} +Buffer.isBuffer = function isBuffer(b) { + return b != null && b._isBuffer === true && b !== Buffer.prototype; // so Buffer.isBuffer(Buffer.prototype) will be false +}; +Buffer.compare = function compare(a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength); + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength); + if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { + throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'); + } + if (a === b) return 0; + let x = a.length; + let y = b.length; + for (let i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break; + } + } + if (x < y) return -1; + if (y < x) return 1; + return 0; +}; +Buffer.isEncoding = function isEncoding(encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true; + default: + return false; + } +}; +Buffer.concat = function concat(list, length) { + if (!Array.isArray(list)) { + throw new TypeError('"list" argument must be an Array of Buffers'); + } + if (list.length === 0) { + return Buffer.alloc(0); + } + let i; + if (length === undefined) { + length = 0; + for (i = 0; i < list.length; ++i) { + length += list[i].length; + } + } + const buffer = Buffer.allocUnsafe(length); + let pos = 0; + for (i = 0; i < list.length; ++i) { + let buf = list[i]; + if (isInstance(buf, Uint8Array)) { + if (pos + buf.length > buffer.length) { + if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf); + buf.copy(buffer, pos); + } else { + Uint8Array.prototype.set.call(buffer, buf, pos); + } + } else if (!Buffer.isBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers'); + } else { + buf.copy(buffer, pos); + } + pos += buf.length; + } + return buffer; +}; +function byteLength(string, encoding) { + if (Buffer.isBuffer(string)) { + return string.length; + } + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { + return string.byteLength; + } + if (typeof string !== 'string') { + throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + 'Received type ' + typeof string); + } + const len = string.length; + const mustMatch = arguments.length > 2 && arguments[2] === true; + if (!mustMatch && len === 0) return 0; + + // Use a for loop to avoid recursion + let loweredCase = false; + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len; + case 'utf8': + case 'utf-8': + return utf8ToBytes(string).length; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2; + case 'hex': + return len >>> 1; + case 'base64': + return base64ToBytes(string).length; + default: + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length; // assume utf8 + } + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; + } + } +} +Buffer.byteLength = byteLength; +function slowToString(encoding, start, end) { + let loweredCase = false; + + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. + + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0; + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return ''; + } + if (end === undefined || end > this.length) { + end = this.length; + } + if (end <= 0) { + return ''; + } + + // Force coercion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0; + start >>>= 0; + if (end <= start) { + return ''; + } + if (!encoding) encoding = 'utf8'; + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end); + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end); + case 'ascii': + return asciiSlice(this, start, end); + case 'latin1': + case 'binary': + return latin1Slice(this, start, end); + case 'base64': + return base64Slice(this, start, end); + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end); + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding); + encoding = (encoding + '').toLowerCase(); + loweredCase = true; + } + } +} + +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 +Buffer.prototype._isBuffer = true; +function swap(b, n, m) { + const i = b[n]; + b[n] = b[m]; + b[m] = i; +} +Buffer.prototype.swap16 = function swap16() { + const len = this.length; + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits'); + } + for (let i = 0; i < len; i += 2) { + swap(this, i, i + 1); + } + return this; +}; +Buffer.prototype.swap32 = function swap32() { + const len = this.length; + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits'); + } + for (let i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this; +}; +Buffer.prototype.swap64 = function swap64() { + const len = this.length; + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits'); + } + for (let i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); + } + return this; +}; +Buffer.prototype.toString = function toString() { + const length = this.length; + if (length === 0) return ''; + if (arguments.length === 0) return utf8Slice(this, 0, length); + return slowToString.apply(this, arguments); +}; +Buffer.prototype.toLocaleString = Buffer.prototype.toString; +Buffer.prototype.equals = function equals(b) { + if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer'); + if (this === b) return true; + return Buffer.compare(this, b) === 0; +}; +Buffer.prototype.inspect = function inspect() { + let str = ''; + const max = exports.h2; + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim(); + if (this.length > max) str += ' ... '; + return ''; +}; +if (customInspectSymbol) { + Buffer.prototype[customInspectSymbol] = Buffer.prototype.inspect; +} +Buffer.prototype.compare = function compare(target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength); + } + if (!Buffer.isBuffer(target)) { + throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. ' + 'Received type ' + typeof target); + } + if (start === undefined) { + start = 0; + } + if (end === undefined) { + end = target ? target.length : 0; + } + if (thisStart === undefined) { + thisStart = 0; + } + if (thisEnd === undefined) { + thisEnd = this.length; + } + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index'); + } + if (thisStart >= thisEnd && start >= end) { + return 0; + } + if (thisStart >= thisEnd) { + return -1; + } + if (start >= end) { + return 1; + } + start >>>= 0; + end >>>= 0; + thisStart >>>= 0; + thisEnd >>>= 0; + if (this === target) return 0; + let x = thisEnd - thisStart; + let y = end - start; + const len = Math.min(x, y); + const thisCopy = this.slice(thisStart, thisEnd); + const targetCopy = target.slice(start, end); + for (let i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i]; + y = targetCopy[i]; + break; + } + } + if (x < y) return -1; + if (y < x) return 1; + return 0; +}; + +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1; + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset; + byteOffset = 0; + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff; + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000; + } + byteOffset = +byteOffset; // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : buffer.length - 1; + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset; + if (byteOffset >= buffer.length) { + if (dir) return -1;else byteOffset = buffer.length - 1; + } else if (byteOffset < 0) { + if (dir) byteOffset = 0;else return -1; + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding); + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1; + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir); + } else if (typeof val === 'number') { + val = val & 0xFF; // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset); + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset); + } + } + return arrayIndexOf(buffer, [val], byteOffset, encoding, dir); + } + throw new TypeError('val must be string, number or Buffer'); +} +function arrayIndexOf(arr, val, byteOffset, encoding, dir) { + let indexSize = 1; + let arrLength = arr.length; + let valLength = val.length; + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase(); + if (encoding === 'ucs2' || encoding === 'ucs-2' || encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1; + } + indexSize = 2; + arrLength /= 2; + valLength /= 2; + byteOffset /= 2; + } + } + function read(buf, i) { + if (indexSize === 1) { + return buf[i]; + } else { + return buf.readUInt16BE(i * indexSize); + } + } + let i; + if (dir) { + let foundIndex = -1; + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i; + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize; + } else { + if (foundIndex !== -1) i -= i - foundIndex; + foundIndex = -1; + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; + for (i = byteOffset; i >= 0; i--) { + let found = true; + for (let j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false; + break; + } + } + if (found) return i; + } + } + return -1; +} +Buffer.prototype.includes = function includes(val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1; +}; +Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true); +}; +Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false); +}; +function hexWrite(buf, string, offset, length) { + offset = Number(offset) || 0; + const remaining = buf.length - offset; + if (!length) { + length = remaining; + } else { + length = Number(length); + if (length > remaining) { + length = remaining; + } + } + const strLen = string.length; + if (length > strLen / 2) { + length = strLen / 2; + } + let i; + for (i = 0; i < length; ++i) { + const parsed = parseInt(string.substr(i * 2, 2), 16); + if (numberIsNaN(parsed)) return i; + buf[offset + i] = parsed; + } + return i; +} +function utf8Write(buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length); +} +function asciiWrite(buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length); +} +function base64Write(buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length); +} +function ucs2Write(buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length); +} +Buffer.prototype.write = function write(string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8'; + length = this.length; + offset = 0; + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset; + length = this.length; + offset = 0; + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset >>> 0; + if (isFinite(length)) { + length = length >>> 0; + if (encoding === undefined) encoding = 'utf8'; + } else { + encoding = length; + length = undefined; + } + } else { + throw new Error('Buffer.write(string, encoding, offset[, length]) is no longer supported'); + } + const remaining = this.length - offset; + if (length === undefined || length > remaining) length = remaining; + if (string.length > 0 && (length < 0 || offset < 0) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds'); + } + if (!encoding) encoding = 'utf8'; + let loweredCase = false; + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length); + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length); + case 'ascii': + case 'latin1': + case 'binary': + return asciiWrite(this, string, offset, length); + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length); + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length); + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding); + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; + } + } +}; +Buffer.prototype.toJSON = function toJSON() { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + }; +}; +function base64Slice(buf, start, end) { + if (start === 0 && end === buf.length) { + return base64.fromByteArray(buf); + } else { + return base64.fromByteArray(buf.slice(start, end)); + } +} +function utf8Slice(buf, start, end) { + end = Math.min(buf.length, end); + const res = []; + let i = start; + while (i < end) { + const firstByte = buf[i]; + let codePoint = null; + let bytesPerSequence = firstByte > 0xEF ? 4 : firstByte > 0xDF ? 3 : firstByte > 0xBF ? 2 : 1; + if (i + bytesPerSequence <= end) { + let secondByte, thirdByte, fourthByte, tempCodePoint; + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte; + } + break; + case 2: + secondByte = buf[i + 1]; + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | secondByte & 0x3F; + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint; + } + } + break; + case 3: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | thirdByte & 0x3F; + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint; + } + } + break; + case 4: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + fourthByte = buf[i + 3]; + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | fourthByte & 0x3F; + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint; + } + } + } + } + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD; + bytesPerSequence = 1; + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000; + res.push(codePoint >>> 10 & 0x3FF | 0xD800); + codePoint = 0xDC00 | codePoint & 0x3FF; + } + res.push(codePoint); + i += bytesPerSequence; + } + return decodeCodePointsArray(res); +} + +// Based on http://stackoverflow.com/a/22747272/680742, the browser with +// the lowest limit is Chrome, with 0x10000 args. +// We go 1 magnitude less, for safety +const MAX_ARGUMENTS_LENGTH = 0x1000; +function decodeCodePointsArray(codePoints) { + const len = codePoints.length; + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints); // avoid extra slice() + } + + // Decode in chunks to avoid "call stack size exceeded". + let res = ''; + let i = 0; + while (i < len) { + res += String.fromCharCode.apply(String, codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)); + } + return res; +} +function asciiSlice(buf, start, end) { + let ret = ''; + end = Math.min(buf.length, end); + for (let i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F); + } + return ret; +} +function latin1Slice(buf, start, end) { + let ret = ''; + end = Math.min(buf.length, end); + for (let i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]); + } + return ret; +} +function hexSlice(buf, start, end) { + const len = buf.length; + if (!start || start < 0) start = 0; + if (!end || end < 0 || end > len) end = len; + let out = ''; + for (let i = start; i < end; ++i) { + out += hexSliceLookupTable[buf[i]]; + } + return out; +} +function utf16leSlice(buf, start, end) { + const bytes = buf.slice(start, end); + let res = ''; + // If bytes.length is odd, the last 8 bits must be ignored (same as node.js) + for (let i = 0; i < bytes.length - 1; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); + } + return res; +} +Buffer.prototype.slice = function slice(start, end) { + const len = this.length; + start = ~~start; + end = end === undefined ? len : ~~end; + if (start < 0) { + start += len; + if (start < 0) start = 0; + } else if (start > len) { + start = len; + } + if (end < 0) { + end += len; + if (end < 0) end = 0; + } else if (end > len) { + end = len; + } + if (end < start) end = start; + const newBuf = this.subarray(start, end); + // Return an augmented `Uint8Array` instance + Object.setPrototypeOf(newBuf, Buffer.prototype); + return newBuf; +}; + +/* + * Need to make sure that buffer isn't trying to write out of bounds. + */ +function checkOffset(offset, ext, length) { + if (offset % 1 !== 0 || offset < 0) throw new RangeError('offset is not uint'); + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length'); +} +Buffer.prototype.readUintLE = Buffer.prototype.readUIntLE = function readUIntLE(offset, byteLength, noAssert) { + offset = offset >>> 0; + byteLength = byteLength >>> 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); + let val = this[offset]; + let mul = 1; + let i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; + } + return val; +}; +Buffer.prototype.readUintBE = Buffer.prototype.readUIntBE = function readUIntBE(offset, byteLength, noAssert) { + offset = offset >>> 0; + byteLength = byteLength >>> 0; + if (!noAssert) { + checkOffset(offset, byteLength, this.length); + } + let val = this[offset + --byteLength]; + let mul = 1; + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul; + } + return val; +}; +Buffer.prototype.readUint8 = Buffer.prototype.readUInt8 = function readUInt8(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 1, this.length); + return this[offset]; +}; +Buffer.prototype.readUint16LE = Buffer.prototype.readUInt16LE = function readUInt16LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] | this[offset + 1] << 8; +}; +Buffer.prototype.readUint16BE = Buffer.prototype.readUInt16BE = function readUInt16BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] << 8 | this[offset + 1]; +}; +Buffer.prototype.readUint32LE = Buffer.prototype.readUInt32LE = function readUInt32LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return (this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16) + this[offset + 3] * 0x1000000; +}; +Buffer.prototype.readUint32BE = Buffer.prototype.readUInt32BE = function readUInt32BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return this[offset] * 0x1000000 + (this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]); +}; +Buffer.prototype.readBigUInt64LE = defineBigIntMethod(function readBigUInt64LE(offset) { + offset = offset >>> 0; + validateNumber(offset, 'offset'); + const first = this[offset]; + const last = this[offset + 7]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8); + } + const lo = first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24; + const hi = this[++offset] + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + last * 2 ** 24; + return BigInt(lo) + (BigInt(hi) << BigInt(32)); +}); +Buffer.prototype.readBigUInt64BE = defineBigIntMethod(function readBigUInt64BE(offset) { + offset = offset >>> 0; + validateNumber(offset, 'offset'); + const first = this[offset]; + const last = this[offset + 7]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8); + } + const hi = first * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + this[++offset]; + const lo = this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last; + return (BigInt(hi) << BigInt(32)) + BigInt(lo); +}); +Buffer.prototype.readIntLE = function readIntLE(offset, byteLength, noAssert) { + offset = offset >>> 0; + byteLength = byteLength >>> 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); + let val = this[offset]; + let mul = 1; + let i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; + } + mul *= 0x80; + if (val >= mul) val -= Math.pow(2, 8 * byteLength); + return val; +}; +Buffer.prototype.readIntBE = function readIntBE(offset, byteLength, noAssert) { + offset = offset >>> 0; + byteLength = byteLength >>> 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); + let i = byteLength; + let mul = 1; + let val = this[offset + --i]; + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul; + } + mul *= 0x80; + if (val >= mul) val -= Math.pow(2, 8 * byteLength); + return val; +}; +Buffer.prototype.readInt8 = function readInt8(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 1, this.length); + if (!(this[offset] & 0x80)) return this[offset]; + return (0xff - this[offset] + 1) * -1; +}; +Buffer.prototype.readInt16LE = function readInt16LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + const val = this[offset] | this[offset + 1] << 8; + return val & 0x8000 ? val | 0xFFFF0000 : val; +}; +Buffer.prototype.readInt16BE = function readInt16BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 2, this.length); + const val = this[offset + 1] | this[offset] << 8; + return val & 0x8000 ? val | 0xFFFF0000 : val; +}; +Buffer.prototype.readInt32LE = function readInt32LE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return this[offset] | this[offset + 1] << 8 | this[offset + 2] << 16 | this[offset + 3] << 24; +}; +Buffer.prototype.readInt32BE = function readInt32BE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return this[offset] << 24 | this[offset + 1] << 16 | this[offset + 2] << 8 | this[offset + 3]; +}; +Buffer.prototype.readBigInt64LE = defineBigIntMethod(function readBigInt64LE(offset) { + offset = offset >>> 0; + validateNumber(offset, 'offset'); + const first = this[offset]; + const last = this[offset + 7]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8); + } + const val = this[offset + 4] + this[offset + 5] * 2 ** 8 + this[offset + 6] * 2 ** 16 + (last << 24); // Overflow + + return (BigInt(val) << BigInt(32)) + BigInt(first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 24); +}); +Buffer.prototype.readBigInt64BE = defineBigIntMethod(function readBigInt64BE(offset) { + offset = offset >>> 0; + validateNumber(offset, 'offset'); + const first = this[offset]; + const last = this[offset + 7]; + if (first === undefined || last === undefined) { + boundsError(offset, this.length - 8); + } + const val = (first << 24) + + // Overflow + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + this[++offset]; + return (BigInt(val) << BigInt(32)) + BigInt(this[++offset] * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last); +}); +Buffer.prototype.readFloatLE = function readFloatLE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return ieee754.read(this, offset, true, 23, 4); +}; +Buffer.prototype.readFloatBE = function readFloatBE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 4, this.length); + return ieee754.read(this, offset, false, 23, 4); +}; +Buffer.prototype.readDoubleLE = function readDoubleLE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 8, this.length); + return ieee754.read(this, offset, true, 52, 8); +}; +Buffer.prototype.readDoubleBE = function readDoubleBE(offset, noAssert) { + offset = offset >>> 0; + if (!noAssert) checkOffset(offset, 8, this.length); + return ieee754.read(this, offset, false, 52, 8); +}; +function checkInt(buf, value, offset, ext, max, min) { + if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance'); + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds'); + if (offset + ext > buf.length) throw new RangeError('Index out of range'); +} +Buffer.prototype.writeUintLE = Buffer.prototype.writeUIntLE = function writeUIntLE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset >>> 0; + byteLength = byteLength >>> 0; + if (!noAssert) { + const maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); + } + let mul = 1; + let i = 0; + this[offset] = value & 0xFF; + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = value / mul & 0xFF; + } + return offset + byteLength; +}; +Buffer.prototype.writeUintBE = Buffer.prototype.writeUIntBE = function writeUIntBE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset >>> 0; + byteLength = byteLength >>> 0; + if (!noAssert) { + const maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); + } + let i = byteLength - 1; + let mul = 1; + this[offset + i] = value & 0xFF; + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = value / mul & 0xFF; + } + return offset + byteLength; +}; +Buffer.prototype.writeUint8 = Buffer.prototype.writeUInt8 = function writeUInt8(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); + this[offset] = value & 0xff; + return offset + 1; +}; +Buffer.prototype.writeUint16LE = Buffer.prototype.writeUInt16LE = function writeUInt16LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + this[offset] = value & 0xff; + this[offset + 1] = value >>> 8; + return offset + 2; +}; +Buffer.prototype.writeUint16BE = Buffer.prototype.writeUInt16BE = function writeUInt16BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + this[offset] = value >>> 8; + this[offset + 1] = value & 0xff; + return offset + 2; +}; +Buffer.prototype.writeUint32LE = Buffer.prototype.writeUInt32LE = function writeUInt32LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + this[offset + 3] = value >>> 24; + this[offset + 2] = value >>> 16; + this[offset + 1] = value >>> 8; + this[offset] = value & 0xff; + return offset + 4; +}; +Buffer.prototype.writeUint32BE = Buffer.prototype.writeUInt32BE = function writeUInt32BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + this[offset] = value >>> 24; + this[offset + 1] = value >>> 16; + this[offset + 2] = value >>> 8; + this[offset + 3] = value & 0xff; + return offset + 4; +}; +function wrtBigUInt64LE(buf, value, offset, min, max) { + checkIntBI(value, min, max, buf, offset, 7); + let lo = Number(value & BigInt(0xffffffff)); + buf[offset++] = lo; + lo = lo >> 8; + buf[offset++] = lo; + lo = lo >> 8; + buf[offset++] = lo; + lo = lo >> 8; + buf[offset++] = lo; + let hi = Number(value >> BigInt(32) & BigInt(0xffffffff)); + buf[offset++] = hi; + hi = hi >> 8; + buf[offset++] = hi; + hi = hi >> 8; + buf[offset++] = hi; + hi = hi >> 8; + buf[offset++] = hi; + return offset; +} +function wrtBigUInt64BE(buf, value, offset, min, max) { + checkIntBI(value, min, max, buf, offset, 7); + let lo = Number(value & BigInt(0xffffffff)); + buf[offset + 7] = lo; + lo = lo >> 8; + buf[offset + 6] = lo; + lo = lo >> 8; + buf[offset + 5] = lo; + lo = lo >> 8; + buf[offset + 4] = lo; + let hi = Number(value >> BigInt(32) & BigInt(0xffffffff)); + buf[offset + 3] = hi; + hi = hi >> 8; + buf[offset + 2] = hi; + hi = hi >> 8; + buf[offset + 1] = hi; + hi = hi >> 8; + buf[offset] = hi; + return offset + 8; +} +Buffer.prototype.writeBigUInt64LE = defineBigIntMethod(function writeBigUInt64LE(value, offset = 0) { + return wrtBigUInt64LE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff')); +}); +Buffer.prototype.writeBigUInt64BE = defineBigIntMethod(function writeBigUInt64BE(value, offset = 0) { + return wrtBigUInt64BE(this, value, offset, BigInt(0), BigInt('0xffffffffffffffff')); +}); +Buffer.prototype.writeIntLE = function writeIntLE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + const limit = Math.pow(2, 8 * byteLength - 1); + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } + let i = 0; + let mul = 1; + let sub = 0; + this[offset] = value & 0xFF; + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1; + } + this[offset + i] = (value / mul >> 0) - sub & 0xFF; + } + return offset + byteLength; +}; +Buffer.prototype.writeIntBE = function writeIntBE(value, offset, byteLength, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + const limit = Math.pow(2, 8 * byteLength - 1); + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } + let i = byteLength - 1; + let mul = 1; + let sub = 0; + this[offset + i] = value & 0xFF; + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1; + } + this[offset + i] = (value / mul >> 0) - sub & 0xFF; + } + return offset + byteLength; +}; +Buffer.prototype.writeInt8 = function writeInt8(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80); + if (value < 0) value = 0xff + value + 1; + this[offset] = value & 0xff; + return offset + 1; +}; +Buffer.prototype.writeInt16LE = function writeInt16LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + this[offset] = value & 0xff; + this[offset + 1] = value >>> 8; + return offset + 2; +}; +Buffer.prototype.writeInt16BE = function writeInt16BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + this[offset] = value >>> 8; + this[offset + 1] = value & 0xff; + return offset + 2; +}; +Buffer.prototype.writeInt32LE = function writeInt32LE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + this[offset] = value & 0xff; + this[offset + 1] = value >>> 8; + this[offset + 2] = value >>> 16; + this[offset + 3] = value >>> 24; + return offset + 4; +}; +Buffer.prototype.writeInt32BE = function writeInt32BE(value, offset, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (value < 0) value = 0xffffffff + value + 1; + this[offset] = value >>> 24; + this[offset + 1] = value >>> 16; + this[offset + 2] = value >>> 8; + this[offset + 3] = value & 0xff; + return offset + 4; +}; +Buffer.prototype.writeBigInt64LE = defineBigIntMethod(function writeBigInt64LE(value, offset = 0) { + return wrtBigUInt64LE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff')); +}); +Buffer.prototype.writeBigInt64BE = defineBigIntMethod(function writeBigInt64BE(value, offset = 0) { + return wrtBigUInt64BE(this, value, offset, -BigInt('0x8000000000000000'), BigInt('0x7fffffffffffffff')); +}); +function checkIEEE754(buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range'); + if (offset < 0) throw new RangeError('Index out of range'); +} +function writeFloat(buf, value, offset, littleEndian, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38); + } + ieee754.write(buf, value, offset, littleEndian, 23, 4); + return offset + 4; +} +Buffer.prototype.writeFloatLE = function writeFloatLE(value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert); +}; +Buffer.prototype.writeFloatBE = function writeFloatBE(value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert); +}; +function writeDouble(buf, value, offset, littleEndian, noAssert) { + value = +value; + offset = offset >>> 0; + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308); + } + ieee754.write(buf, value, offset, littleEndian, 52, 8); + return offset + 8; +} +Buffer.prototype.writeDoubleLE = function writeDoubleLE(value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert); +}; +Buffer.prototype.writeDoubleBE = function writeDoubleBE(value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert); +}; + +// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) +Buffer.prototype.copy = function copy(target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer'); + if (!start) start = 0; + if (!end && end !== 0) end = this.length; + if (targetStart >= target.length) targetStart = target.length; + if (!targetStart) targetStart = 0; + if (end > 0 && end < start) end = start; + + // Copy 0 bytes; we're done + if (end === start) return 0; + if (target.length === 0 || this.length === 0) return 0; + + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds'); + } + if (start < 0 || start >= this.length) throw new RangeError('Index out of range'); + if (end < 0) throw new RangeError('sourceEnd out of bounds'); + + // Are we oob? + if (end > this.length) end = this.length; + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start; + } + const len = end - start; + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end); + } else { + Uint8Array.prototype.set.call(target, this.subarray(start, end), targetStart); + } + return len; +}; + +// Usage: +// buffer.fill(number[, offset[, end]]) +// buffer.fill(buffer[, offset[, end]]) +// buffer.fill(string[, offset[, end]][, encoding]) +Buffer.prototype.fill = function fill(val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start; + start = 0; + end = this.length; + } else if (typeof end === 'string') { + encoding = end; + end = this.length; + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string'); + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding); + } + if (val.length === 1) { + const code = val.charCodeAt(0); + if (encoding === 'utf8' && code < 128 || encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code; + } + } + } else if (typeof val === 'number') { + val = val & 255; + } else if (typeof val === 'boolean') { + val = Number(val); + } + + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index'); + } + if (end <= start) { + return this; + } + start = start >>> 0; + end = end === undefined ? this.length : end >>> 0; + if (!val) val = 0; + let i; + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val; + } + } else { + const bytes = Buffer.isBuffer(val) ? val : Buffer.from(val, encoding); + const len = bytes.length; + if (len === 0) { + throw new TypeError('The value "' + val + '" is invalid for argument "value"'); + } + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len]; + } + } + return this; +}; + +// CUSTOM ERRORS +// ============= + +// Simplified versions from Node, changed for Buffer-only usage +const errors = {}; +function E(sym, getMessage, Base) { + errors[sym] = class NodeError extends Base { + constructor() { + super(); + Object.defineProperty(this, 'message', { + value: getMessage.apply(this, arguments), + writable: true, + configurable: true + }); + + // Add the error code to the name to include it in the stack trace. + this.name = `${this.name} [${sym}]`; + // Access the stack to generate the error message including the error code + // from the name. + this.stack; // eslint-disable-line no-unused-expressions + // Reset the name to the actual name. + delete this.name; + } + get code() { + return sym; + } + set code(value) { + Object.defineProperty(this, 'code', { + configurable: true, + enumerable: true, + value, + writable: true + }); + } + toString() { + return `${this.name} [${sym}]: ${this.message}`; + } + }; +} +E('ERR_BUFFER_OUT_OF_BOUNDS', function (name) { + if (name) { + return `${name} is outside of buffer bounds`; + } + return 'Attempt to access memory outside buffer bounds'; +}, RangeError); +E('ERR_INVALID_ARG_TYPE', function (name, actual) { + return `The "${name}" argument must be of type number. Received type ${typeof actual}`; +}, TypeError); +E('ERR_OUT_OF_RANGE', function (str, range, input) { + let msg = `The value of "${str}" is out of range.`; + let received = input; + if (Number.isInteger(input) && Math.abs(input) > 2 ** 32) { + received = addNumericalSeparator(String(input)); + } else if (typeof input === 'bigint') { + received = String(input); + if (input > BigInt(2) ** BigInt(32) || input < -(BigInt(2) ** BigInt(32))) { + received = addNumericalSeparator(received); + } + received += 'n'; + } + msg += ` It must be ${range}. Received ${received}`; + return msg; +}, RangeError); +function addNumericalSeparator(val) { + let res = ''; + let i = val.length; + const start = val[0] === '-' ? 1 : 0; + for (; i >= start + 4; i -= 3) { + res = `_${val.slice(i - 3, i)}${res}`; + } + return `${val.slice(0, i)}${res}`; +} + +// CHECK FUNCTIONS +// =============== + +function checkBounds(buf, offset, byteLength) { + validateNumber(offset, 'offset'); + if (buf[offset] === undefined || buf[offset + byteLength] === undefined) { + boundsError(offset, buf.length - (byteLength + 1)); + } +} +function checkIntBI(value, min, max, buf, offset, byteLength) { + if (value > max || value < min) { + const n = typeof min === 'bigint' ? 'n' : ''; + let range; + if (byteLength > 3) { + if (min === 0 || min === BigInt(0)) { + range = `>= 0${n} and < 2${n} ** ${(byteLength + 1) * 8}${n}`; + } else { + range = `>= -(2${n} ** ${(byteLength + 1) * 8 - 1}${n}) and < 2 ** ` + `${(byteLength + 1) * 8 - 1}${n}`; + } + } else { + range = `>= ${min}${n} and <= ${max}${n}`; + } + throw new errors.ERR_OUT_OF_RANGE('value', range, value); + } + checkBounds(buf, offset, byteLength); +} +function validateNumber(value, name) { + if (typeof value !== 'number') { + throw new errors.ERR_INVALID_ARG_TYPE(name, 'number', value); + } +} +function boundsError(value, length, type) { + if (Math.floor(value) !== value) { + validateNumber(value, type); + throw new errors.ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value); + } + if (length < 0) { + throw new errors.ERR_BUFFER_OUT_OF_BOUNDS(); + } + throw new errors.ERR_OUT_OF_RANGE(type || 'offset', `>= ${type ? 1 : 0} and <= ${length}`, value); +} + +// HELPER FUNCTIONS +// ================ + +const INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g; +function base64clean(str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0]; + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = str.trim().replace(INVALID_BASE64_RE, ''); + // Node converts strings with length < 2 to '' + if (str.length < 2) return ''; + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '='; + } + return str; +} +function utf8ToBytes(string, units) { + units = units || Infinity; + let codePoint; + const length = string.length; + let leadSurrogate = null; + const bytes = []; + for (let i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i); + + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + continue; + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + continue; + } + + // valid lead + leadSurrogate = codePoint; + continue; + } + + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + leadSurrogate = codePoint; + continue; + } + + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + } + leadSurrogate = null; + + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break; + bytes.push(codePoint); + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break; + bytes.push(codePoint >> 0x6 | 0xC0, codePoint & 0x3F | 0x80); + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break; + bytes.push(codePoint >> 0xC | 0xE0, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80); + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break; + bytes.push(codePoint >> 0x12 | 0xF0, codePoint >> 0xC & 0x3F | 0x80, codePoint >> 0x6 & 0x3F | 0x80, codePoint & 0x3F | 0x80); + } else { + throw new Error('Invalid code point'); + } + } + return bytes; +} +function asciiToBytes(str) { + const byteArray = []; + for (let i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF); + } + return byteArray; +} +function utf16leToBytes(str, units) { + let c, hi, lo; + const byteArray = []; + for (let i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break; + c = str.charCodeAt(i); + hi = c >> 8; + lo = c % 256; + byteArray.push(lo); + byteArray.push(hi); + } + return byteArray; +} +function base64ToBytes(str) { + return base64.toByteArray(base64clean(str)); +} +function blitBuffer(src, dst, offset, length) { + let i; + for (i = 0; i < length; ++i) { + if (i + offset >= dst.length || i >= src.length) break; + dst[i + offset] = src[i]; + } + return i; +} + +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance(obj, type) { + return obj instanceof type || obj != null && obj.constructor != null && obj.constructor.name != null && obj.constructor.name === type.name; +} +function numberIsNaN(obj) { + // For IE11 support + return obj !== obj; // eslint-disable-line no-self-compare +} + +// Create lookup table for `toString('hex')` +// See: https://github.com/feross/buffer/issues/219 +const hexSliceLookupTable = function () { + const alphabet = '0123456789abcdef'; + const table = new Array(256); + for (let i = 0; i < 16; ++i) { + const i16 = i * 16; + for (let j = 0; j < 16; ++j) { + table[i16 + j] = alphabet[i] + alphabet[j]; + } + } + return table; +}(); + +// Return not function with Error if BigInt not supported +function defineBigIntMethod(fn) { + return typeof BigInt === 'undefined' ? BufferBigIntNotDefined : fn; +} +function BufferBigIntNotDefined() { + throw new Error('BigInt not supported'); +} + +/***/ }), + +/***/ 3737: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var GetIntrinsic = __webpack_require__(55050); +var callBind = __webpack_require__(68375); +var $indexOf = callBind(GetIntrinsic('String.prototype.indexOf')); +module.exports = function callBoundIntrinsic(name, allowMissing) { + var intrinsic = GetIntrinsic(name, !!allowMissing); + if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { + return callBind(intrinsic); + } + return intrinsic; +}; + +/***/ }), + +/***/ 68375: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var bind = __webpack_require__(36046); +var GetIntrinsic = __webpack_require__(55050); +var setFunctionLength = __webpack_require__(23954); +var $TypeError = GetIntrinsic('%TypeError%'); +var $apply = GetIntrinsic('%Function.prototype.apply%'); +var $call = GetIntrinsic('%Function.prototype.call%'); +var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply); +var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); +var $max = GetIntrinsic('%Math.max%'); +if ($defineProperty) { + try { + $defineProperty({}, 'a', { + value: 1 + }); + } catch (e) { + // IE 8 has a broken defineProperty + $defineProperty = null; + } +} +module.exports = function callBind(originalFunction) { + if (typeof originalFunction !== 'function') { + throw new $TypeError('a function is required'); + } + var func = $reflectApply(bind, $call, arguments); + return setFunctionLength(func, 1 + $max(0, originalFunction.length - (arguments.length - 1)), true); +}; +var applyBind = function applyBind() { + return $reflectApply(bind, $apply, arguments); +}; +if ($defineProperty) { + $defineProperty(module.exports, 'apply', { + value: applyBind + }); +} else { + module.exports.apply = applyBind; +} + +/***/ }), + +/***/ 91037: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var hasPropertyDescriptors = __webpack_require__(96757)(); +var GetIntrinsic = __webpack_require__(55050); +var $defineProperty = hasPropertyDescriptors && GetIntrinsic('%Object.defineProperty%', true); +if ($defineProperty) { + try { + $defineProperty({}, 'a', { + value: 1 + }); + } catch (e) { + // IE 8 has a broken defineProperty + $defineProperty = false; + } +} +var $SyntaxError = GetIntrinsic('%SyntaxError%'); +var $TypeError = GetIntrinsic('%TypeError%'); +var gopd = __webpack_require__(12319); + +/** @type {(obj: Record, property: PropertyKey, value: unknown, nonEnumerable?: boolean | null, nonWritable?: boolean | null, nonConfigurable?: boolean | null, loose?: boolean) => void} */ +module.exports = function defineDataProperty(obj, property, value) { + if (!obj || typeof obj !== 'object' && typeof obj !== 'function') { + throw new $TypeError('`obj` must be an object or a function`'); + } + if (typeof property !== 'string' && typeof property !== 'symbol') { + throw new $TypeError('`property` must be a string or a symbol`'); + } + if (arguments.length > 3 && typeof arguments[3] !== 'boolean' && arguments[3] !== null) { + throw new $TypeError('`nonEnumerable`, if provided, must be a boolean or null'); + } + if (arguments.length > 4 && typeof arguments[4] !== 'boolean' && arguments[4] !== null) { + throw new $TypeError('`nonWritable`, if provided, must be a boolean or null'); + } + if (arguments.length > 5 && typeof arguments[5] !== 'boolean' && arguments[5] !== null) { + throw new $TypeError('`nonConfigurable`, if provided, must be a boolean or null'); + } + if (arguments.length > 6 && typeof arguments[6] !== 'boolean') { + throw new $TypeError('`loose`, if provided, must be a boolean'); + } + var nonEnumerable = arguments.length > 3 ? arguments[3] : null; + var nonWritable = arguments.length > 4 ? arguments[4] : null; + var nonConfigurable = arguments.length > 5 ? arguments[5] : null; + var loose = arguments.length > 6 ? arguments[6] : false; + + /* @type {false | TypedPropertyDescriptor} */ + var desc = !!gopd && gopd(obj, property); + if ($defineProperty) { + $defineProperty(obj, property, { + configurable: nonConfigurable === null && desc ? desc.configurable : !nonConfigurable, + enumerable: nonEnumerable === null && desc ? desc.enumerable : !nonEnumerable, + value: value, + writable: nonWritable === null && desc ? desc.writable : !nonWritable + }); + } else if (loose || !nonEnumerable && !nonWritable && !nonConfigurable) { + // must fall back to [[Set]], and was not explicitly asked to make non-enumerable, non-writable, or non-configurable + obj[property] = value; // eslint-disable-line no-param-reassign + } else { + throw new $SyntaxError('This environment does not support defining a property as non-configurable, non-writable, or non-enumerable.'); + } +}; + +/***/ }), + +/***/ 51820: +/***/ ((module) => { + +"use strict"; + + +/* eslint no-invalid-this: 1 */ +var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; +var toStr = Object.prototype.toString; +var max = Math.max; +var funcType = '[object Function]'; +var concatty = function concatty(a, b) { + var arr = []; + for (var i = 0; i < a.length; i += 1) { + arr[i] = a[i]; + } + for (var j = 0; j < b.length; j += 1) { + arr[j + a.length] = b[j]; + } + return arr; +}; +var slicy = function slicy(arrLike, offset) { + var arr = []; + for (var i = offset || 0, j = 0; i < arrLike.length; i += 1, j += 1) { + arr[j] = arrLike[i]; + } + return arr; +}; +var joiny = function (arr, joiner) { + var str = ''; + for (var i = 0; i < arr.length; i += 1) { + str += arr[i]; + if (i + 1 < arr.length) { + str += joiner; + } + } + return str; +}; +module.exports = function bind(that) { + var target = this; + if (typeof target !== 'function' || toStr.apply(target) !== funcType) { + throw new TypeError(ERROR_MESSAGE + target); + } + var args = slicy(arguments, 1); + var bound; + var binder = function () { + if (this instanceof bound) { + var result = target.apply(this, concatty(args, arguments)); + if (Object(result) === result) { + return result; + } + return this; + } + return target.apply(that, concatty(args, arguments)); + }; + var boundLength = max(0, target.length - args.length); + var boundArgs = []; + for (var i = 0; i < boundLength; i++) { + boundArgs[i] = '$' + i; + } + bound = Function('binder', 'return function (' + joiny(boundArgs, ',') + '){ return binder.apply(this,arguments); }')(binder); + if (target.prototype) { + var Empty = function Empty() {}; + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; + } + return bound; +}; + +/***/ }), + +/***/ 36046: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var implementation = __webpack_require__(51820); +module.exports = Function.prototype.bind || implementation; + +/***/ }), + +/***/ 55050: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var undefined; +var $SyntaxError = SyntaxError; +var $Function = Function; +var $TypeError = TypeError; + +// eslint-disable-next-line consistent-return +var getEvalledConstructor = function (expressionSyntax) { + try { + return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); + } catch (e) {} +}; +var $gOPD = Object.getOwnPropertyDescriptor; +if ($gOPD) { + try { + $gOPD({}, ''); + } catch (e) { + $gOPD = null; // this is IE 8, which has a broken gOPD + } +} +var throwTypeError = function () { + throw new $TypeError(); +}; +var ThrowTypeError = $gOPD ? function () { + try { + // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties + arguments.callee; // IE 8 does not throw here + return throwTypeError; + } catch (calleeThrows) { + try { + // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') + return $gOPD(arguments, 'callee').get; + } catch (gOPDthrows) { + return throwTypeError; + } + } +}() : throwTypeError; +var hasSymbols = __webpack_require__(8269)(); +var hasProto = __webpack_require__(1886)(); +var getProto = Object.getPrototypeOf || (hasProto ? function (x) { + return x.__proto__; +} // eslint-disable-line no-proto +: null); +var needsEval = {}; +var TypedArray = typeof Uint8Array === 'undefined' || !getProto ? undefined : getProto(Uint8Array); +var INTRINSICS = { + '%AggregateError%': typeof AggregateError === 'undefined' ? undefined : AggregateError, + '%Array%': Array, + '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined : ArrayBuffer, + '%ArrayIteratorPrototype%': hasSymbols && getProto ? getProto([][Symbol.iterator]()) : undefined, + '%AsyncFromSyncIteratorPrototype%': undefined, + '%AsyncFunction%': needsEval, + '%AsyncGenerator%': needsEval, + '%AsyncGeneratorFunction%': needsEval, + '%AsyncIteratorPrototype%': needsEval, + '%Atomics%': typeof Atomics === 'undefined' ? undefined : Atomics, + '%BigInt%': typeof BigInt === 'undefined' ? undefined : BigInt, + '%BigInt64Array%': typeof BigInt64Array === 'undefined' ? undefined : BigInt64Array, + '%BigUint64Array%': typeof BigUint64Array === 'undefined' ? undefined : BigUint64Array, + '%Boolean%': Boolean, + '%DataView%': typeof DataView === 'undefined' ? undefined : DataView, + '%Date%': Date, + '%decodeURI%': decodeURI, + '%decodeURIComponent%': decodeURIComponent, + '%encodeURI%': encodeURI, + '%encodeURIComponent%': encodeURIComponent, + '%Error%': Error, + '%eval%': eval, + // eslint-disable-line no-eval + '%EvalError%': EvalError, + '%Float32Array%': typeof Float32Array === 'undefined' ? undefined : Float32Array, + '%Float64Array%': typeof Float64Array === 'undefined' ? undefined : Float64Array, + '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined : FinalizationRegistry, + '%Function%': $Function, + '%GeneratorFunction%': needsEval, + '%Int8Array%': typeof Int8Array === 'undefined' ? undefined : Int8Array, + '%Int16Array%': typeof Int16Array === 'undefined' ? undefined : Int16Array, + '%Int32Array%': typeof Int32Array === 'undefined' ? undefined : Int32Array, + '%isFinite%': isFinite, + '%isNaN%': isNaN, + '%IteratorPrototype%': hasSymbols && getProto ? getProto(getProto([][Symbol.iterator]())) : undefined, + '%JSON%': typeof JSON === 'object' ? JSON : undefined, + '%Map%': typeof Map === 'undefined' ? undefined : Map, + '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Map()[Symbol.iterator]()), + '%Math%': Math, + '%Number%': Number, + '%Object%': Object, + '%parseFloat%': parseFloat, + '%parseInt%': parseInt, + '%Promise%': typeof Promise === 'undefined' ? undefined : Promise, + '%Proxy%': typeof Proxy === 'undefined' ? undefined : Proxy, + '%RangeError%': RangeError, + '%ReferenceError%': ReferenceError, + '%Reflect%': typeof Reflect === 'undefined' ? undefined : Reflect, + '%RegExp%': RegExp, + '%Set%': typeof Set === 'undefined' ? undefined : Set, + '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols || !getProto ? undefined : getProto(new Set()[Symbol.iterator]()), + '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined : SharedArrayBuffer, + '%String%': String, + '%StringIteratorPrototype%': hasSymbols && getProto ? getProto(''[Symbol.iterator]()) : undefined, + '%Symbol%': hasSymbols ? Symbol : undefined, + '%SyntaxError%': $SyntaxError, + '%ThrowTypeError%': ThrowTypeError, + '%TypedArray%': TypedArray, + '%TypeError%': $TypeError, + '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined : Uint8Array, + '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined : Uint8ClampedArray, + '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined : Uint16Array, + '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined : Uint32Array, + '%URIError%': URIError, + '%WeakMap%': typeof WeakMap === 'undefined' ? undefined : WeakMap, + '%WeakRef%': typeof WeakRef === 'undefined' ? undefined : WeakRef, + '%WeakSet%': typeof WeakSet === 'undefined' ? undefined : WeakSet +}; +if (getProto) { + try { + null.error; // eslint-disable-line no-unused-expressions + } catch (e) { + // https://github.com/tc39/proposal-shadowrealm/pull/384#issuecomment-1364264229 + var errorProto = getProto(getProto(e)); + INTRINSICS['%Error.prototype%'] = errorProto; + } +} +var doEval = function doEval(name) { + var value; + if (name === '%AsyncFunction%') { + value = getEvalledConstructor('async function () {}'); + } else if (name === '%GeneratorFunction%') { + value = getEvalledConstructor('function* () {}'); + } else if (name === '%AsyncGeneratorFunction%') { + value = getEvalledConstructor('async function* () {}'); + } else if (name === '%AsyncGenerator%') { + var fn = doEval('%AsyncGeneratorFunction%'); + if (fn) { + value = fn.prototype; + } + } else if (name === '%AsyncIteratorPrototype%') { + var gen = doEval('%AsyncGenerator%'); + if (gen && getProto) { + value = getProto(gen.prototype); + } + } + INTRINSICS[name] = value; + return value; +}; +var LEGACY_ALIASES = { + '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], + '%ArrayPrototype%': ['Array', 'prototype'], + '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], + '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], + '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], + '%ArrayProto_values%': ['Array', 'prototype', 'values'], + '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], + '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], + '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], + '%BooleanPrototype%': ['Boolean', 'prototype'], + '%DataViewPrototype%': ['DataView', 'prototype'], + '%DatePrototype%': ['Date', 'prototype'], + '%ErrorPrototype%': ['Error', 'prototype'], + '%EvalErrorPrototype%': ['EvalError', 'prototype'], + '%Float32ArrayPrototype%': ['Float32Array', 'prototype'], + '%Float64ArrayPrototype%': ['Float64Array', 'prototype'], + '%FunctionPrototype%': ['Function', 'prototype'], + '%Generator%': ['GeneratorFunction', 'prototype'], + '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'], + '%Int8ArrayPrototype%': ['Int8Array', 'prototype'], + '%Int16ArrayPrototype%': ['Int16Array', 'prototype'], + '%Int32ArrayPrototype%': ['Int32Array', 'prototype'], + '%JSONParse%': ['JSON', 'parse'], + '%JSONStringify%': ['JSON', 'stringify'], + '%MapPrototype%': ['Map', 'prototype'], + '%NumberPrototype%': ['Number', 'prototype'], + '%ObjectPrototype%': ['Object', 'prototype'], + '%ObjProto_toString%': ['Object', 'prototype', 'toString'], + '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'], + '%PromisePrototype%': ['Promise', 'prototype'], + '%PromiseProto_then%': ['Promise', 'prototype', 'then'], + '%Promise_all%': ['Promise', 'all'], + '%Promise_reject%': ['Promise', 'reject'], + '%Promise_resolve%': ['Promise', 'resolve'], + '%RangeErrorPrototype%': ['RangeError', 'prototype'], + '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'], + '%RegExpPrototype%': ['RegExp', 'prototype'], + '%SetPrototype%': ['Set', 'prototype'], + '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'], + '%StringPrototype%': ['String', 'prototype'], + '%SymbolPrototype%': ['Symbol', 'prototype'], + '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'], + '%TypedArrayPrototype%': ['TypedArray', 'prototype'], + '%TypeErrorPrototype%': ['TypeError', 'prototype'], + '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'], + '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'], + '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'], + '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'], + '%URIErrorPrototype%': ['URIError', 'prototype'], + '%WeakMapPrototype%': ['WeakMap', 'prototype'], + '%WeakSetPrototype%': ['WeakSet', 'prototype'] +}; +var bind = __webpack_require__(36046); +var hasOwn = __webpack_require__(1261); +var $concat = bind.call(Function.call, Array.prototype.concat); +var $spliceApply = bind.call(Function.apply, Array.prototype.splice); +var $replace = bind.call(Function.call, String.prototype.replace); +var $strSlice = bind.call(Function.call, String.prototype.slice); +var $exec = bind.call(Function.call, RegExp.prototype.exec); + +/* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ +var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; +var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */ +var stringToPath = function stringToPath(string) { + var first = $strSlice(string, 0, 1); + var last = $strSlice(string, -1); + if (first === '%' && last !== '%') { + throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`'); + } else if (last === '%' && first !== '%') { + throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`'); + } + var result = []; + $replace(string, rePropName, function (match, number, quote, subString) { + result[result.length] = quote ? $replace(subString, reEscapeChar, '$1') : number || match; + }); + return result; +}; +/* end adaptation */ + +var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) { + var intrinsicName = name; + var alias; + if (hasOwn(LEGACY_ALIASES, intrinsicName)) { + alias = LEGACY_ALIASES[intrinsicName]; + intrinsicName = '%' + alias[0] + '%'; + } + if (hasOwn(INTRINSICS, intrinsicName)) { + var value = INTRINSICS[intrinsicName]; + if (value === needsEval) { + value = doEval(intrinsicName); + } + if (typeof value === 'undefined' && !allowMissing) { + throw new $TypeError('intrinsic ' + name + ' exists, but is not available. Please file an issue!'); + } + return { + alias: alias, + name: intrinsicName, + value: value + }; + } + throw new $SyntaxError('intrinsic ' + name + ' does not exist!'); +}; +module.exports = function GetIntrinsic(name, allowMissing) { + if (typeof name !== 'string' || name.length === 0) { + throw new $TypeError('intrinsic name must be a non-empty string'); + } + if (arguments.length > 1 && typeof allowMissing !== 'boolean') { + throw new $TypeError('"allowMissing" argument must be a boolean'); + } + if ($exec(/^%?[^%]*%?$/, name) === null) { + throw new $SyntaxError('`%` may not be present anywhere but at the beginning and end of the intrinsic name'); + } + var parts = stringToPath(name); + var intrinsicBaseName = parts.length > 0 ? parts[0] : ''; + var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing); + var intrinsicRealName = intrinsic.name; + var value = intrinsic.value; + var skipFurtherCaching = false; + var alias = intrinsic.alias; + if (alias) { + intrinsicBaseName = alias[0]; + $spliceApply(parts, $concat([0, 1], alias)); + } + for (var i = 1, isOwn = true; i < parts.length; i += 1) { + var part = parts[i]; + var first = $strSlice(part, 0, 1); + var last = $strSlice(part, -1); + if ((first === '"' || first === "'" || first === '`' || last === '"' || last === "'" || last === '`') && first !== last) { + throw new $SyntaxError('property names with quotes must have matching quotes'); + } + if (part === 'constructor' || !isOwn) { + skipFurtherCaching = true; + } + intrinsicBaseName += '.' + part; + intrinsicRealName = '%' + intrinsicBaseName + '%'; + if (hasOwn(INTRINSICS, intrinsicRealName)) { + value = INTRINSICS[intrinsicRealName]; + } else if (value != null) { + if (!(part in value)) { + if (!allowMissing) { + throw new $TypeError('base intrinsic for ' + name + ' exists, but the property is not available.'); + } + return void undefined; + } + if ($gOPD && i + 1 >= parts.length) { + var desc = $gOPD(value, part); + isOwn = !!desc; + + // By convention, when a data property is converted to an accessor + // property to emulate a data property that does not suffer from + // the override mistake, that accessor's getter is marked with + // an `originalValue` property. Here, when we detect this, we + // uphold the illusion by pretending to see that original data + // property, i.e., returning the value rather than the getter + // itself. + if (isOwn && 'get' in desc && !('originalValue' in desc.get)) { + value = desc.get; + } else { + value = value[part]; + } + } else { + isOwn = hasOwn(value, part); + value = value[part]; + } + if (isOwn && !skipFurtherCaching) { + INTRINSICS[intrinsicRealName] = value; + } + } + } + return value; +}; + +/***/ }), + +/***/ 12319: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var GetIntrinsic = __webpack_require__(55050); +var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); +if ($gOPD) { + try { + $gOPD([], 'length'); + } catch (e) { + // IE 8 has a broken gOPD + $gOPD = null; + } +} +module.exports = $gOPD; + +/***/ }), + +/***/ 96757: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var GetIntrinsic = __webpack_require__(55050); +var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); +var hasPropertyDescriptors = function hasPropertyDescriptors() { + if ($defineProperty) { + try { + $defineProperty({}, 'a', { + value: 1 + }); + return true; + } catch (e) { + // IE 8 has a broken defineProperty + return false; + } + } + return false; +}; +hasPropertyDescriptors.hasArrayLengthDefineBug = function hasArrayLengthDefineBug() { + // node v0.6 has a bug where array lengths can be Set but not Defined + if (!hasPropertyDescriptors()) { + return null; + } + try { + return $defineProperty([], 'length', { + value: 1 + }).length !== 1; + } catch (e) { + // In Firefox 4-22, defining length on an array throws an exception. + return true; + } +}; +module.exports = hasPropertyDescriptors; + +/***/ }), + +/***/ 1886: +/***/ ((module) => { + +"use strict"; + + +var test = { + foo: {} +}; +var $Object = Object; +module.exports = function hasProto() { + return { + __proto__: test + }.foo === test.foo && !({ + __proto__: null + } instanceof $Object); +}; + +/***/ }), + +/***/ 8269: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var origSymbol = typeof Symbol !== 'undefined' && Symbol; +var hasSymbolSham = __webpack_require__(88928); +module.exports = function hasNativeSymbols() { + if (typeof origSymbol !== 'function') { + return false; + } + if (typeof Symbol !== 'function') { + return false; + } + if (typeof origSymbol('foo') !== 'symbol') { + return false; + } + if (typeof Symbol('bar') !== 'symbol') { + return false; + } + return hasSymbolSham(); +}; + +/***/ }), + +/***/ 88928: +/***/ ((module) => { + +"use strict"; + + +/* eslint complexity: [2, 18], max-statements: [2, 33] */ +module.exports = function hasSymbols() { + if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { + return false; + } + if (typeof Symbol.iterator === 'symbol') { + return true; + } + var obj = {}; + var sym = Symbol('test'); + var symObj = Object(sym); + if (typeof sym === 'string') { + return false; + } + if (Object.prototype.toString.call(sym) !== '[object Symbol]') { + return false; + } + if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { + return false; + } + + // temp disabled per https://github.com/ljharb/object.assign/issues/17 + // if (sym instanceof Symbol) { return false; } + // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 + // if (!(symObj instanceof Symbol)) { return false; } + + // if (typeof Symbol.prototype.toString !== 'function') { return false; } + // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } + + var symVal = 42; + obj[sym] = symVal; + for (sym in obj) { + return false; + } // eslint-disable-line no-restricted-syntax, no-unreachable-loop + if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { + return false; + } + if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { + return false; + } + var syms = Object.getOwnPropertySymbols(obj); + if (syms.length !== 1 || syms[0] !== sym) { + return false; + } + if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { + return false; + } + if (typeof Object.getOwnPropertyDescriptor === 'function') { + var descriptor = Object.getOwnPropertyDescriptor(obj, sym); + if (descriptor.value !== symVal || descriptor.enumerable !== true) { + return false; + } + } + return true; +}; + +/***/ }), + +/***/ 1261: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var call = Function.prototype.call; +var $hasOwn = Object.prototype.hasOwnProperty; +var bind = __webpack_require__(36046); + +/** @type {(o: {}, p: PropertyKey) => p is keyof o} */ +module.exports = bind.call(call, $hasOwn); + +/***/ }), + +/***/ 14709: +/***/ ((__unused_webpack_module, exports) => { + +/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ +exports.read = function (buffer, offset, isLE, mLen, nBytes) { + var e, m; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var nBits = -7; + var i = isLE ? nBytes - 1 : 0; + var d = isLE ? -1 : 1; + var s = buffer[offset + i]; + i += d; + e = s & (1 << -nBits) - 1; + s >>= -nBits; + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + m = e & (1 << -nBits) - 1; + e >>= -nBits; + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : (s ? -1 : 1) * Infinity; + } else { + m = m + Math.pow(2, mLen); + e = e - eBias; + } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen); +}; +exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0; + var i = isLE ? 0 : nBytes - 1; + var d = isLE ? 1 : -1; + var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0; + value = Math.abs(value); + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} + e = e << mLen | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} + buffer[offset + i - d] |= s * 128; +}; + +/***/ }), + +/***/ 87676: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +var hasMap = typeof Map === 'function' && Map.prototype; +var mapSizeDescriptor = Object.getOwnPropertyDescriptor && hasMap ? Object.getOwnPropertyDescriptor(Map.prototype, 'size') : null; +var mapSize = hasMap && mapSizeDescriptor && typeof mapSizeDescriptor.get === 'function' ? mapSizeDescriptor.get : null; +var mapForEach = hasMap && Map.prototype.forEach; +var hasSet = typeof Set === 'function' && Set.prototype; +var setSizeDescriptor = Object.getOwnPropertyDescriptor && hasSet ? Object.getOwnPropertyDescriptor(Set.prototype, 'size') : null; +var setSize = hasSet && setSizeDescriptor && typeof setSizeDescriptor.get === 'function' ? setSizeDescriptor.get : null; +var setForEach = hasSet && Set.prototype.forEach; +var hasWeakMap = typeof WeakMap === 'function' && WeakMap.prototype; +var weakMapHas = hasWeakMap ? WeakMap.prototype.has : null; +var hasWeakSet = typeof WeakSet === 'function' && WeakSet.prototype; +var weakSetHas = hasWeakSet ? WeakSet.prototype.has : null; +var hasWeakRef = typeof WeakRef === 'function' && WeakRef.prototype; +var weakRefDeref = hasWeakRef ? WeakRef.prototype.deref : null; +var booleanValueOf = Boolean.prototype.valueOf; +var objectToString = Object.prototype.toString; +var functionToString = Function.prototype.toString; +var $match = String.prototype.match; +var $slice = String.prototype.slice; +var $replace = String.prototype.replace; +var $toUpperCase = String.prototype.toUpperCase; +var $toLowerCase = String.prototype.toLowerCase; +var $test = RegExp.prototype.test; +var $concat = Array.prototype.concat; +var $join = Array.prototype.join; +var $arrSlice = Array.prototype.slice; +var $floor = Math.floor; +var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null; +var gOPS = Object.getOwnPropertySymbols; +var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null; +var hasShammedSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'object'; +// ie, `has-tostringtag/shams +var toStringTag = typeof Symbol === 'function' && Symbol.toStringTag && (typeof Symbol.toStringTag === hasShammedSymbols ? 'object' : 'symbol') ? Symbol.toStringTag : null; +var isEnumerable = Object.prototype.propertyIsEnumerable; +var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || ([].__proto__ === Array.prototype // eslint-disable-line no-proto +? function (O) { + return O.__proto__; // eslint-disable-line no-proto +} : null); +function addNumericSeparator(num, str) { + if (num === Infinity || num === -Infinity || num !== num || num && num > -1000 && num < 1000 || $test.call(/e/, str)) { + return str; + } + var sepRegex = /[0-9](?=(?:[0-9]{3})+(?![0-9]))/g; + if (typeof num === 'number') { + var int = num < 0 ? -$floor(-num) : $floor(num); // trunc(num) + if (int !== num) { + var intStr = String(int); + var dec = $slice.call(str, intStr.length + 1); + return $replace.call(intStr, sepRegex, '$&_') + '.' + $replace.call($replace.call(dec, /([0-9]{3})/g, '$&_'), /_$/, ''); + } + } + return $replace.call(str, sepRegex, '$&_'); +} +var utilInspect = __webpack_require__(53260); +var inspectCustom = utilInspect.custom; +var inspectSymbol = isSymbol(inspectCustom) ? inspectCustom : null; +module.exports = function inspect_(obj, options, depth, seen) { + var opts = options || {}; + if (has(opts, 'quoteStyle') && opts.quoteStyle !== 'single' && opts.quoteStyle !== 'double') { + throw new TypeError('option "quoteStyle" must be "single" or "double"'); + } + if (has(opts, 'maxStringLength') && (typeof opts.maxStringLength === 'number' ? opts.maxStringLength < 0 && opts.maxStringLength !== Infinity : opts.maxStringLength !== null)) { + throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`'); + } + var customInspect = has(opts, 'customInspect') ? opts.customInspect : true; + if (typeof customInspect !== 'boolean' && customInspect !== 'symbol') { + throw new TypeError('option "customInspect", if provided, must be `true`, `false`, or `\'symbol\'`'); + } + if (has(opts, 'indent') && opts.indent !== null && opts.indent !== '\t' && !(parseInt(opts.indent, 10) === opts.indent && opts.indent > 0)) { + throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`'); + } + if (has(opts, 'numericSeparator') && typeof opts.numericSeparator !== 'boolean') { + throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`'); + } + var numericSeparator = opts.numericSeparator; + if (typeof obj === 'undefined') { + return 'undefined'; + } + if (obj === null) { + return 'null'; + } + if (typeof obj === 'boolean') { + return obj ? 'true' : 'false'; + } + if (typeof obj === 'string') { + return inspectString(obj, opts); + } + if (typeof obj === 'number') { + if (obj === 0) { + return Infinity / obj > 0 ? '0' : '-0'; + } + var str = String(obj); + return numericSeparator ? addNumericSeparator(obj, str) : str; + } + if (typeof obj === 'bigint') { + var bigIntStr = String(obj) + 'n'; + return numericSeparator ? addNumericSeparator(obj, bigIntStr) : bigIntStr; + } + var maxDepth = typeof opts.depth === 'undefined' ? 5 : opts.depth; + if (typeof depth === 'undefined') { + depth = 0; + } + if (depth >= maxDepth && maxDepth > 0 && typeof obj === 'object') { + return isArray(obj) ? '[Array]' : '[Object]'; + } + var indent = getIndent(opts, depth); + if (typeof seen === 'undefined') { + seen = []; + } else if (indexOf(seen, obj) >= 0) { + return '[Circular]'; + } + function inspect(value, from, noIndent) { + if (from) { + seen = $arrSlice.call(seen); + seen.push(from); + } + if (noIndent) { + var newOpts = { + depth: opts.depth + }; + if (has(opts, 'quoteStyle')) { + newOpts.quoteStyle = opts.quoteStyle; + } + return inspect_(value, newOpts, depth + 1, seen); + } + return inspect_(value, opts, depth + 1, seen); + } + if (typeof obj === 'function' && !isRegExp(obj)) { + // in older engines, regexes are callable + var name = nameOf(obj); + var keys = arrObjKeys(obj, inspect); + return '[Function' + (name ? ': ' + name : ' (anonymous)') + ']' + (keys.length > 0 ? ' { ' + $join.call(keys, ', ') + ' }' : ''); + } + if (isSymbol(obj)) { + var symString = hasShammedSymbols ? $replace.call(String(obj), /^(Symbol\(.*\))_[^)]*$/, '$1') : symToString.call(obj); + return typeof obj === 'object' && !hasShammedSymbols ? markBoxed(symString) : symString; + } + if (isElement(obj)) { + var s = '<' + $toLowerCase.call(String(obj.nodeName)); + var attrs = obj.attributes || []; + for (var i = 0; i < attrs.length; i++) { + s += ' ' + attrs[i].name + '=' + wrapQuotes(quote(attrs[i].value), 'double', opts); + } + s += '>'; + if (obj.childNodes && obj.childNodes.length) { + s += '...'; + } + s += ''; + return s; + } + if (isArray(obj)) { + if (obj.length === 0) { + return '[]'; + } + var xs = arrObjKeys(obj, inspect); + if (indent && !singleLineValues(xs)) { + return '[' + indentedJoin(xs, indent) + ']'; + } + return '[ ' + $join.call(xs, ', ') + ' ]'; + } + if (isError(obj)) { + var parts = arrObjKeys(obj, inspect); + if (!('cause' in Error.prototype) && 'cause' in obj && !isEnumerable.call(obj, 'cause')) { + return '{ [' + String(obj) + '] ' + $join.call($concat.call('[cause]: ' + inspect(obj.cause), parts), ', ') + ' }'; + } + if (parts.length === 0) { + return '[' + String(obj) + ']'; + } + return '{ [' + String(obj) + '] ' + $join.call(parts, ', ') + ' }'; + } + if (typeof obj === 'object' && customInspect) { + if (inspectSymbol && typeof obj[inspectSymbol] === 'function' && utilInspect) { + return utilInspect(obj, { + depth: maxDepth - depth + }); + } else if (customInspect !== 'symbol' && typeof obj.inspect === 'function') { + return obj.inspect(); + } + } + if (isMap(obj)) { + var mapParts = []; + if (mapForEach) { + mapForEach.call(obj, function (value, key) { + mapParts.push(inspect(key, obj, true) + ' => ' + inspect(value, obj)); + }); + } + return collectionOf('Map', mapSize.call(obj), mapParts, indent); + } + if (isSet(obj)) { + var setParts = []; + if (setForEach) { + setForEach.call(obj, function (value) { + setParts.push(inspect(value, obj)); + }); + } + return collectionOf('Set', setSize.call(obj), setParts, indent); + } + if (isWeakMap(obj)) { + return weakCollectionOf('WeakMap'); + } + if (isWeakSet(obj)) { + return weakCollectionOf('WeakSet'); + } + if (isWeakRef(obj)) { + return weakCollectionOf('WeakRef'); + } + if (isNumber(obj)) { + return markBoxed(inspect(Number(obj))); + } + if (isBigInt(obj)) { + return markBoxed(inspect(bigIntValueOf.call(obj))); + } + if (isBoolean(obj)) { + return markBoxed(booleanValueOf.call(obj)); + } + if (isString(obj)) { + return markBoxed(inspect(String(obj))); + } + // note: in IE 8, sometimes `global !== window` but both are the prototypes of each other + /* eslint-env browser */ + if (typeof window !== 'undefined' && obj === window) { + return '{ [object Window] }'; + } + if (obj === __webpack_require__.g) { + return '{ [object globalThis] }'; + } + if (!isDate(obj) && !isRegExp(obj)) { + var ys = arrObjKeys(obj, inspect); + var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object; + var protoTag = obj instanceof Object ? '' : 'null prototype'; + var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? 'Object' : ''; + var constructorTag = isPlainObject || typeof obj.constructor !== 'function' ? '' : obj.constructor.name ? obj.constructor.name + ' ' : ''; + var tag = constructorTag + (stringTag || protoTag ? '[' + $join.call($concat.call([], stringTag || [], protoTag || []), ': ') + '] ' : ''); + if (ys.length === 0) { + return tag + '{}'; + } + if (indent) { + return tag + '{' + indentedJoin(ys, indent) + '}'; + } + return tag + '{ ' + $join.call(ys, ', ') + ' }'; + } + return String(obj); +}; +function wrapQuotes(s, defaultStyle, opts) { + var quoteChar = (opts.quoteStyle || defaultStyle) === 'double' ? '"' : "'"; + return quoteChar + s + quoteChar; +} +function quote(s) { + return $replace.call(String(s), /"/g, '"'); +} +function isArray(obj) { + return toStr(obj) === '[object Array]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} +function isDate(obj) { + return toStr(obj) === '[object Date]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} +function isRegExp(obj) { + return toStr(obj) === '[object RegExp]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} +function isError(obj) { + return toStr(obj) === '[object Error]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} +function isString(obj) { + return toStr(obj) === '[object String]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} +function isNumber(obj) { + return toStr(obj) === '[object Number]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} +function isBoolean(obj) { + return toStr(obj) === '[object Boolean]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); +} + +// Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives +function isSymbol(obj) { + if (hasShammedSymbols) { + return obj && typeof obj === 'object' && obj instanceof Symbol; + } + if (typeof obj === 'symbol') { + return true; + } + if (!obj || typeof obj !== 'object' || !symToString) { + return false; + } + try { + symToString.call(obj); + return true; + } catch (e) {} + return false; +} +function isBigInt(obj) { + if (!obj || typeof obj !== 'object' || !bigIntValueOf) { + return false; + } + try { + bigIntValueOf.call(obj); + return true; + } catch (e) {} + return false; +} +var hasOwn = Object.prototype.hasOwnProperty || function (key) { + return key in this; +}; +function has(obj, key) { + return hasOwn.call(obj, key); +} +function toStr(obj) { + return objectToString.call(obj); +} +function nameOf(f) { + if (f.name) { + return f.name; + } + var m = $match.call(functionToString.call(f), /^function\s*([\w$]+)/); + if (m) { + return m[1]; + } + return null; +} +function indexOf(xs, x) { + if (xs.indexOf) { + return xs.indexOf(x); + } + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) { + return i; + } + } + return -1; +} +function isMap(x) { + if (!mapSize || !x || typeof x !== 'object') { + return false; + } + try { + mapSize.call(x); + try { + setSize.call(x); + } catch (s) { + return true; + } + return x instanceof Map; // core-js workaround, pre-v2.5.0 + } catch (e) {} + return false; +} +function isWeakMap(x) { + if (!weakMapHas || !x || typeof x !== 'object') { + return false; + } + try { + weakMapHas.call(x, weakMapHas); + try { + weakSetHas.call(x, weakSetHas); + } catch (s) { + return true; + } + return x instanceof WeakMap; // core-js workaround, pre-v2.5.0 + } catch (e) {} + return false; +} +function isWeakRef(x) { + if (!weakRefDeref || !x || typeof x !== 'object') { + return false; + } + try { + weakRefDeref.call(x); + return true; + } catch (e) {} + return false; +} +function isSet(x) { + if (!setSize || !x || typeof x !== 'object') { + return false; + } + try { + setSize.call(x); + try { + mapSize.call(x); + } catch (m) { + return true; + } + return x instanceof Set; // core-js workaround, pre-v2.5.0 + } catch (e) {} + return false; +} +function isWeakSet(x) { + if (!weakSetHas || !x || typeof x !== 'object') { + return false; + } + try { + weakSetHas.call(x, weakSetHas); + try { + weakMapHas.call(x, weakMapHas); + } catch (s) { + return true; + } + return x instanceof WeakSet; // core-js workaround, pre-v2.5.0 + } catch (e) {} + return false; +} +function isElement(x) { + if (!x || typeof x !== 'object') { + return false; + } + if (typeof HTMLElement !== 'undefined' && x instanceof HTMLElement) { + return true; + } + return typeof x.nodeName === 'string' && typeof x.getAttribute === 'function'; +} +function inspectString(str, opts) { + if (str.length > opts.maxStringLength) { + var remaining = str.length - opts.maxStringLength; + var trailer = '... ' + remaining + ' more character' + (remaining > 1 ? 's' : ''); + return inspectString($slice.call(str, 0, opts.maxStringLength), opts) + trailer; + } + // eslint-disable-next-line no-control-regex + var s = $replace.call($replace.call(str, /(['\\])/g, '\\$1'), /[\x00-\x1f]/g, lowbyte); + return wrapQuotes(s, 'single', opts); +} +function lowbyte(c) { + var n = c.charCodeAt(0); + var x = { + 8: 'b', + 9: 't', + 10: 'n', + 12: 'f', + 13: 'r' + }[n]; + if (x) { + return '\\' + x; + } + return '\\x' + (n < 0x10 ? '0' : '') + $toUpperCase.call(n.toString(16)); +} +function markBoxed(str) { + return 'Object(' + str + ')'; +} +function weakCollectionOf(type) { + return type + ' { ? }'; +} +function collectionOf(type, size, entries, indent) { + var joinedEntries = indent ? indentedJoin(entries, indent) : $join.call(entries, ', '); + return type + ' (' + size + ') {' + joinedEntries + '}'; +} +function singleLineValues(xs) { + for (var i = 0; i < xs.length; i++) { + if (indexOf(xs[i], '\n') >= 0) { + return false; + } + } + return true; +} +function getIndent(opts, depth) { + var baseIndent; + if (opts.indent === '\t') { + baseIndent = '\t'; + } else if (typeof opts.indent === 'number' && opts.indent > 0) { + baseIndent = $join.call(Array(opts.indent + 1), ' '); + } else { + return null; + } + return { + base: baseIndent, + prev: $join.call(Array(depth + 1), baseIndent) + }; +} +function indentedJoin(xs, indent) { + if (xs.length === 0) { + return ''; + } + var lineJoiner = '\n' + indent.prev + indent.base; + return lineJoiner + $join.call(xs, ',' + lineJoiner) + '\n' + indent.prev; +} +function arrObjKeys(obj, inspect) { + var isArr = isArray(obj); + var xs = []; + if (isArr) { + xs.length = obj.length; + for (var i = 0; i < obj.length; i++) { + xs[i] = has(obj, i) ? inspect(obj[i], obj) : ''; + } + } + var syms = typeof gOPS === 'function' ? gOPS(obj) : []; + var symMap; + if (hasShammedSymbols) { + symMap = {}; + for (var k = 0; k < syms.length; k++) { + symMap['$' + syms[k]] = syms[k]; + } + } + for (var key in obj) { + // eslint-disable-line no-restricted-syntax + if (!has(obj, key)) { + continue; + } // eslint-disable-line no-restricted-syntax, no-continue + if (isArr && String(Number(key)) === key && key < obj.length) { + continue; + } // eslint-disable-line no-restricted-syntax, no-continue + if (hasShammedSymbols && symMap['$' + key] instanceof Symbol) { + // this is to prevent shammed Symbols, which are stored as strings, from being included in the string key section + continue; // eslint-disable-line no-restricted-syntax, no-continue + } else if ($test.call(/[^\w$]/, key)) { + xs.push(inspect(key, obj) + ': ' + inspect(obj[key], obj)); + } else { + xs.push(key + ': ' + inspect(obj[key], obj)); + } + } + if (typeof gOPS === 'function') { + for (var j = 0; j < syms.length; j++) { + if (isEnumerable.call(obj, syms[j])) { + xs.push('[' + inspect(syms[j]) + ']: ' + inspect(obj[syms[j]], obj)); + } + } + } + return xs; +} + +/***/ }), + +/***/ 14375: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; +/* provided dependency */ var process = __webpack_require__(71624); +// 'path' module extracted from Node.js v8.11.1 (only the posix part) +// transplited with Babel + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + + + +function assertPath(path) { + if (typeof path !== 'string') { + throw new TypeError('Path must be a string. Received ' + JSON.stringify(path)); + } +} + +// Resolves . and .. elements in a path with directory names +function normalizeStringPosix(path, allowAboveRoot) { + var res = ''; + var lastSegmentLength = 0; + var lastSlash = -1; + var dots = 0; + var code; + for (var i = 0; i <= path.length; ++i) { + if (i < path.length) code = path.charCodeAt(i);else if (code === 47 /*/*/) break;else code = 47 /*/*/; + if (code === 47 /*/*/) { + if (lastSlash === i - 1 || dots === 1) { + // NOOP + } else if (lastSlash !== i - 1 && dots === 2) { + if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) { + if (res.length > 2) { + var lastSlashIndex = res.lastIndexOf('/'); + if (lastSlashIndex !== res.length - 1) { + if (lastSlashIndex === -1) { + res = ''; + lastSegmentLength = 0; + } else { + res = res.slice(0, lastSlashIndex); + lastSegmentLength = res.length - 1 - res.lastIndexOf('/'); + } + lastSlash = i; + dots = 0; + continue; + } + } else if (res.length === 2 || res.length === 1) { + res = ''; + lastSegmentLength = 0; + lastSlash = i; + dots = 0; + continue; + } + } + if (allowAboveRoot) { + if (res.length > 0) res += '/..';else res = '..'; + lastSegmentLength = 2; + } + } else { + if (res.length > 0) res += '/' + path.slice(lastSlash + 1, i);else res = path.slice(lastSlash + 1, i); + lastSegmentLength = i - lastSlash - 1; + } + lastSlash = i; + dots = 0; + } else if (code === 46 /*.*/ && dots !== -1) { + ++dots; + } else { + dots = -1; + } + } + return res; +} +function _format(sep, pathObject) { + var dir = pathObject.dir || pathObject.root; + var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || ''); + if (!dir) { + return base; + } + if (dir === pathObject.root) { + return dir + base; + } + return dir + sep + base; +} +var posix = { + // path.resolve([from ...], to) + resolve: function resolve() { + var resolvedPath = ''; + var resolvedAbsolute = false; + var cwd; + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path; + if (i >= 0) path = arguments[i];else { + if (cwd === undefined) cwd = process.cwd(); + path = cwd; + } + assertPath(path); + + // Skip empty entries + if (path.length === 0) { + continue; + } + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/; + } + + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + + // Normalize the path + resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute); + if (resolvedAbsolute) { + if (resolvedPath.length > 0) return '/' + resolvedPath;else return '/'; + } else if (resolvedPath.length > 0) { + return resolvedPath; + } else { + return '.'; + } + }, + normalize: function normalize(path) { + assertPath(path); + if (path.length === 0) return '.'; + var isAbsolute = path.charCodeAt(0) === 47 /*/*/; + var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/; + + // Normalize the path + path = normalizeStringPosix(path, !isAbsolute); + if (path.length === 0 && !isAbsolute) path = '.'; + if (path.length > 0 && trailingSeparator) path += '/'; + if (isAbsolute) return '/' + path; + return path; + }, + isAbsolute: function isAbsolute(path) { + assertPath(path); + return path.length > 0 && path.charCodeAt(0) === 47 /*/*/; + }, + join: function join() { + if (arguments.length === 0) return '.'; + var joined; + for (var i = 0; i < arguments.length; ++i) { + var arg = arguments[i]; + assertPath(arg); + if (arg.length > 0) { + if (joined === undefined) joined = arg;else joined += '/' + arg; + } + } + if (joined === undefined) return '.'; + return posix.normalize(joined); + }, + relative: function relative(from, to) { + assertPath(from); + assertPath(to); + if (from === to) return ''; + from = posix.resolve(from); + to = posix.resolve(to); + if (from === to) return ''; + + // Trim any leading backslashes + var fromStart = 1; + for (; fromStart < from.length; ++fromStart) { + if (from.charCodeAt(fromStart) !== 47 /*/*/) break; + } + var fromEnd = from.length; + var fromLen = fromEnd - fromStart; + + // Trim any leading backslashes + var toStart = 1; + for (; toStart < to.length; ++toStart) { + if (to.charCodeAt(toStart) !== 47 /*/*/) break; + } + var toEnd = to.length; + var toLen = toEnd - toStart; + + // Compare paths to find the longest common path from root + var length = fromLen < toLen ? fromLen : toLen; + var lastCommonSep = -1; + var i = 0; + for (; i <= length; ++i) { + if (i === length) { + if (toLen > length) { + if (to.charCodeAt(toStart + i) === 47 /*/*/) { + // We get here if `from` is the exact base path for `to`. + // For example: from='/foo/bar'; to='/foo/bar/baz' + return to.slice(toStart + i + 1); + } else if (i === 0) { + // We get here if `from` is the root + // For example: from='/'; to='/foo' + return to.slice(toStart + i); + } + } else if (fromLen > length) { + if (from.charCodeAt(fromStart + i) === 47 /*/*/) { + // We get here if `to` is the exact base path for `from`. + // For example: from='/foo/bar/baz'; to='/foo/bar' + lastCommonSep = i; + } else if (i === 0) { + // We get here if `to` is the root. + // For example: from='/foo'; to='/' + lastCommonSep = 0; + } + } + break; + } + var fromCode = from.charCodeAt(fromStart + i); + var toCode = to.charCodeAt(toStart + i); + if (fromCode !== toCode) break;else if (fromCode === 47 /*/*/) lastCommonSep = i; + } + var out = ''; + // Generate the relative path based on the path difference between `to` + // and `from` + for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { + if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) { + if (out.length === 0) out += '..';else out += '/..'; + } + } + + // Lastly, append the rest of the destination (`to`) path that comes after + // the common path parts + if (out.length > 0) return out + to.slice(toStart + lastCommonSep);else { + toStart += lastCommonSep; + if (to.charCodeAt(toStart) === 47 /*/*/) ++toStart; + return to.slice(toStart); + } + }, + _makeLong: function _makeLong(path) { + return path; + }, + dirname: function dirname(path) { + assertPath(path); + if (path.length === 0) return '.'; + var code = path.charCodeAt(0); + var hasRoot = code === 47 /*/*/; + var end = -1; + var matchedSlash = true; + for (var i = path.length - 1; i >= 1; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + if (!matchedSlash) { + end = i; + break; + } + } else { + // We saw the first non-path separator + matchedSlash = false; + } + } + if (end === -1) return hasRoot ? '/' : '.'; + if (hasRoot && end === 1) return '//'; + return path.slice(0, end); + }, + basename: function basename(path, ext) { + if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string'); + assertPath(path); + var start = 0; + var end = -1; + var matchedSlash = true; + var i; + if (ext !== undefined && ext.length > 0 && ext.length <= path.length) { + if (ext.length === path.length && ext === path) return ''; + var extIdx = ext.length - 1; + var firstNonSlashEnd = -1; + for (i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else { + if (firstNonSlashEnd === -1) { + // We saw the first non-path separator, remember this index in case + // we need it if the extension ends up not matching + matchedSlash = false; + firstNonSlashEnd = i + 1; + } + if (extIdx >= 0) { + // Try to match the explicit extension + if (code === ext.charCodeAt(extIdx)) { + if (--extIdx === -1) { + // We matched the extension, so mark this as the end of our path + // component + end = i; + } + } else { + // Extension does not match, so our result is the entire path + // component + extIdx = -1; + end = firstNonSlashEnd; + } + } + } + } + if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length; + return path.slice(start, end); + } else { + for (i = path.length - 1; i >= 0; --i) { + if (path.charCodeAt(i) === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + start = i + 1; + break; + } + } else if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // path component + matchedSlash = false; + end = i + 1; + } + } + if (end === -1) return ''; + return path.slice(start, end); + } + }, + extname: function extname(path) { + assertPath(path); + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + for (var i = path.length - 1; i >= 0; --i) { + var code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46 /*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + return ''; + } + return path.slice(startDot, end); + }, + format: function format(pathObject) { + if (pathObject === null || typeof pathObject !== 'object') { + throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject); + } + return _format('/', pathObject); + }, + parse: function parse(path) { + assertPath(path); + var ret = { + root: '', + dir: '', + base: '', + ext: '', + name: '' + }; + if (path.length === 0) return ret; + var code = path.charCodeAt(0); + var isAbsolute = code === 47 /*/*/; + var start; + if (isAbsolute) { + ret.root = '/'; + start = 1; + } else { + start = 0; + } + var startDot = -1; + var startPart = 0; + var end = -1; + var matchedSlash = true; + var i = path.length - 1; + + // Track the state of characters (if any) we see before our first dot and + // after any path separator we find + var preDotState = 0; + + // Get non-dir info + for (; i >= start; --i) { + code = path.charCodeAt(i); + if (code === 47 /*/*/) { + // If we reached a path separator that was not part of a set of path + // separators at the end of the string, stop now + if (!matchedSlash) { + startPart = i + 1; + break; + } + continue; + } + if (end === -1) { + // We saw the first non-path separator, mark this as the end of our + // extension + matchedSlash = false; + end = i + 1; + } + if (code === 46 /*.*/) { + // If this is our first dot, mark it as the start of our extension + if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1; + } else if (startDot !== -1) { + // We saw a non-dot and non-path separator before our dot, so we should + // have a good chance at having a non-empty extension + preDotState = -1; + } + } + if (startDot === -1 || end === -1 || + // We saw a non-dot character immediately before the dot + preDotState === 0 || + // The (right-most) trimmed path component is exactly '..' + preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) { + if (end !== -1) { + if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end); + } + } else { + if (startPart === 0 && isAbsolute) { + ret.name = path.slice(1, startDot); + ret.base = path.slice(1, end); + } else { + ret.name = path.slice(startPart, startDot); + ret.base = path.slice(startPart, end); + } + ret.ext = path.slice(startDot, end); + } + if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/'; + return ret; + }, + sep: '/', + delimiter: ':', + win32: null, + posix: null +}; +posix.posix = posix; +module.exports = posix; + +/***/ }), + +/***/ 71624: +/***/ ((module) => { + +// shim for using process in browser +var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout() { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +})(); +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch (e) { + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch (e) { + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e) { + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e) { + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } +} +var queue = []; +var draining = false; +var currentQueue; +var queueIndex = -1; +function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } +} +function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; + var len = queue.length; + while (len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} +process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } +}; + +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; +function noop() {} +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; +process.listeners = function (name) { + return []; +}; +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; +process.cwd = function () { + return '/'; +}; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function () { + return 0; +}; + +/***/ }), + +/***/ 43277: +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ decode: () => (/* binding */ decode), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), +/* harmony export */ encode: () => (/* binding */ encode), +/* harmony export */ toASCII: () => (/* binding */ toASCII), +/* harmony export */ toUnicode: () => (/* binding */ toUnicode), +/* harmony export */ ucs2decode: () => (/* binding */ ucs2decode), +/* harmony export */ ucs2encode: () => (/* binding */ ucs2encode) +/* harmony export */ }); + + +/** Highest positive signed 32-bit float value */ +const maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1 + +/** Bootstring parameters */ +const base = 36; +const tMin = 1; +const tMax = 26; +const skew = 38; +const damp = 700; +const initialBias = 72; +const initialN = 128; // 0x80 +const delimiter = '-'; // '\x2D' + +/** Regular expressions */ +const regexPunycode = /^xn--/; +const regexNonASCII = /[^\0-\x7F]/; // Note: U+007F DEL is excluded too. +const regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators + +/** Error messages */ +const errors = { + 'overflow': 'Overflow: input needs wider integers to process', + 'not-basic': 'Illegal input >= 0x80 (not a basic code point)', + 'invalid-input': 'Invalid input' +}; + +/** Convenience shortcuts */ +const baseMinusTMin = base - tMin; +const floor = Math.floor; +const stringFromCharCode = String.fromCharCode; + +/*--------------------------------------------------------------------------*/ + +/** + * A generic error utility function. + * @private + * @param {String} type The error type. + * @returns {Error} Throws a `RangeError` with the applicable error message. + */ +function error(type) { + throw new RangeError(errors[type]); +} + +/** + * A generic `Array#map` utility function. + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function that gets called for every array + * item. + * @returns {Array} A new array of values returned by the callback function. + */ +function map(array, callback) { + const result = []; + let length = array.length; + while (length--) { + result[length] = callback(array[length]); + } + return result; +} + +/** + * A simple `Array#map`-like wrapper to work with domain name strings or email + * addresses. + * @private + * @param {String} domain The domain name or email address. + * @param {Function} callback The function that gets called for every + * character. + * @returns {String} A new string of characters returned by the callback + * function. + */ +function mapDomain(domain, callback) { + const parts = domain.split('@'); + let result = ''; + if (parts.length > 1) { + // In email addresses, only the domain name should be punycoded. Leave + // the local part (i.e. everything up to `@`) intact. + result = parts[0] + '@'; + domain = parts[1]; + } + // Avoid `split(regex)` for IE8 compatibility. See #17. + domain = domain.replace(regexSeparators, '\x2E'); + const labels = domain.split('.'); + const encoded = map(labels, callback).join('.'); + return result + encoded; +} + +/** + * Creates an array containing the numeric code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, + * this function will convert a pair of surrogate halves (each of which + * UCS-2 exposes as separate characters) into a single code point, + * matching UTF-16. + * @see `punycode.ucs2.encode` + * @see + * @memberOf punycode.ucs2 + * @name decode + * @param {String} string The Unicode input string (UCS-2). + * @returns {Array} The new array of code points. + */ +function ucs2decode(string) { + const output = []; + let counter = 0; + const length = string.length; + while (counter < length) { + const value = string.charCodeAt(counter++); + if (value >= 0xD800 && value <= 0xDBFF && counter < length) { + // It's a high surrogate, and there is a next character. + const extra = string.charCodeAt(counter++); + if ((extra & 0xFC00) == 0xDC00) { + // Low surrogate. + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000); + } else { + // It's an unmatched surrogate; only append this code unit, in case the + // next code unit is the high surrogate of a surrogate pair. + output.push(value); + counter--; + } + } else { + output.push(value); + } + } + return output; +} + +/** + * Creates a string based on an array of numeric code points. + * @see `punycode.ucs2.decode` + * @memberOf punycode.ucs2 + * @name encode + * @param {Array} codePoints The array of numeric code points. + * @returns {String} The new Unicode string (UCS-2). + */ +const ucs2encode = codePoints => String.fromCodePoint(...codePoints); + +/** + * Converts a basic code point into a digit/integer. + * @see `digitToBasic()` + * @private + * @param {Number} codePoint The basic numeric code point value. + * @returns {Number} The numeric value of a basic code point (for use in + * representing integers) in the range `0` to `base - 1`, or `base` if + * the code point does not represent a value. + */ +const basicToDigit = function (codePoint) { + if (codePoint >= 0x30 && codePoint < 0x3A) { + return 26 + (codePoint - 0x30); + } + if (codePoint >= 0x41 && codePoint < 0x5B) { + return codePoint - 0x41; + } + if (codePoint >= 0x61 && codePoint < 0x7B) { + return codePoint - 0x61; + } + return base; +}; + +/** + * Converts a digit/integer into a basic code point. + * @see `basicToDigit()` + * @private + * @param {Number} digit The numeric value of a basic code point. + * @returns {Number} The basic code point whose value (when used for + * representing integers) is `digit`, which needs to be in the range + * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is + * used; else, the lowercase form is used. The behavior is undefined + * if `flag` is non-zero and `digit` has no uppercase form. + */ +const digitToBasic = function (digit, flag) { + // 0..25 map to ASCII a..z or A..Z + // 26..35 map to ASCII 0..9 + return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5); +}; + +/** + * Bias adaptation function as per section 3.4 of RFC 3492. + * https://tools.ietf.org/html/rfc3492#section-3.4 + * @private + */ +const adapt = function (delta, numPoints, firstTime) { + let k = 0; + delta = firstTime ? floor(delta / damp) : delta >> 1; + delta += floor(delta / numPoints); + for /* no initialization */ + (; delta > baseMinusTMin * tMax >> 1; k += base) { + delta = floor(delta / baseMinusTMin); + } + return floor(k + (baseMinusTMin + 1) * delta / (delta + skew)); +}; + +/** + * Converts a Punycode string of ASCII-only symbols to a string of Unicode + * symbols. + * @memberOf punycode + * @param {String} input The Punycode string of ASCII-only symbols. + * @returns {String} The resulting string of Unicode symbols. + */ +const decode = function (input) { + // Don't use UCS-2. + const output = []; + const inputLength = input.length; + let i = 0; + let n = initialN; + let bias = initialBias; + + // Handle the basic code points: let `basic` be the number of input code + // points before the last delimiter, or `0` if there is none, then copy + // the first basic code points to the output. + + let basic = input.lastIndexOf(delimiter); + if (basic < 0) { + basic = 0; + } + for (let j = 0; j < basic; ++j) { + // if it's not a basic code point + if (input.charCodeAt(j) >= 0x80) { + error('not-basic'); + } + output.push(input.charCodeAt(j)); + } + + // Main decoding loop: start just after the last delimiter if any basic code + // points were copied; start at the beginning otherwise. + + for /* no final expression */ + (let index = basic > 0 ? basic + 1 : 0; index < inputLength;) { + // `index` is the index of the next character to be consumed. + // Decode a generalized variable-length integer into `delta`, + // which gets added to `i`. The overflow checking is easier + // if we increase `i` as we go, then subtract off its starting + // value at the end to obtain `delta`. + const oldi = i; + for /* no condition */ + (let w = 1, k = base;; k += base) { + if (index >= inputLength) { + error('invalid-input'); + } + const digit = basicToDigit(input.charCodeAt(index++)); + if (digit >= base) { + error('invalid-input'); + } + if (digit > floor((maxInt - i) / w)) { + error('overflow'); + } + i += digit * w; + const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + if (digit < t) { + break; + } + const baseMinusT = base - t; + if (w > floor(maxInt / baseMinusT)) { + error('overflow'); + } + w *= baseMinusT; + } + const out = output.length + 1; + bias = adapt(i - oldi, out, oldi == 0); + + // `i` was supposed to wrap around from `out` to `0`, + // incrementing `n` each time, so we'll fix that now: + if (floor(i / out) > maxInt - n) { + error('overflow'); + } + n += floor(i / out); + i %= out; + + // Insert `n` at position `i` of the output. + output.splice(i++, 0, n); + } + return String.fromCodePoint(...output); +}; + +/** + * Converts a string of Unicode symbols (e.g. a domain name label) to a + * Punycode string of ASCII-only symbols. + * @memberOf punycode + * @param {String} input The string of Unicode symbols. + * @returns {String} The resulting Punycode string of ASCII-only symbols. + */ +const encode = function (input) { + const output = []; + + // Convert the input in UCS-2 to an array of Unicode code points. + input = ucs2decode(input); + + // Cache the length. + const inputLength = input.length; + + // Initialize the state. + let n = initialN; + let delta = 0; + let bias = initialBias; + + // Handle the basic code points. + for (const currentValue of input) { + if (currentValue < 0x80) { + output.push(stringFromCharCode(currentValue)); + } + } + const basicLength = output.length; + let handledCPCount = basicLength; + + // `handledCPCount` is the number of code points that have been handled; + // `basicLength` is the number of basic code points. + + // Finish the basic string with a delimiter unless it's empty. + if (basicLength) { + output.push(delimiter); + } + + // Main encoding loop: + while (handledCPCount < inputLength) { + // All non-basic code points < n have been handled already. Find the next + // larger one: + let m = maxInt; + for (const currentValue of input) { + if (currentValue >= n && currentValue < m) { + m = currentValue; + } + } + + // Increase `delta` enough to advance the decoder's state to , + // but guard against overflow. + const handledCPCountPlusOne = handledCPCount + 1; + if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) { + error('overflow'); + } + delta += (m - n) * handledCPCountPlusOne; + n = m; + for (const currentValue of input) { + if (currentValue < n && ++delta > maxInt) { + error('overflow'); + } + if (currentValue === n) { + // Represent delta as a generalized variable-length integer. + let q = delta; + for /* no condition */ + (let k = base;; k += base) { + const t = k <= bias ? tMin : k >= bias + tMax ? tMax : k - bias; + if (q < t) { + break; + } + const qMinusT = q - t; + const baseMinusT = base - t; + output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))); + q = floor(qMinusT / baseMinusT); + } + output.push(stringFromCharCode(digitToBasic(q, 0))); + bias = adapt(delta, handledCPCountPlusOne, handledCPCount === basicLength); + delta = 0; + ++handledCPCount; + } + } + ++delta; + ++n; + } + return output.join(''); +}; + +/** + * Converts a Punycode string representing a domain name or an email address + * to Unicode. Only the Punycoded parts of the input will be converted, i.e. + * it doesn't matter if you call it on a string that has already been + * converted to Unicode. + * @memberOf punycode + * @param {String} input The Punycoded domain name or email address to + * convert to Unicode. + * @returns {String} The Unicode representation of the given Punycode + * string. + */ +const toUnicode = function (input) { + return mapDomain(input, function (string) { + return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string; + }); +}; + +/** + * Converts a Unicode string representing a domain name or an email address to + * Punycode. Only the non-ASCII parts of the domain name will be converted, + * i.e. it doesn't matter if you call it with a domain that's already in + * ASCII. + * @memberOf punycode + * @param {String} input The domain name or email address to convert, as a + * Unicode string. + * @returns {String} The Punycode representation of the given domain name or + * email address. + */ +const toASCII = function (input) { + return mapDomain(input, function (string) { + return regexNonASCII.test(string) ? 'xn--' + encode(string) : string; + }); +}; + +/*--------------------------------------------------------------------------*/ + +/** Define the public API */ +const punycode = { + /** + * A string representing the current Punycode.js version number. + * @memberOf punycode + * @type String + */ + 'version': '2.3.1', + /** + * An object of methods to convert from JavaScript's internal character + * representation (UCS-2) to Unicode code points, and back. + * @see + * @memberOf punycode + * @type Object + */ + 'ucs2': { + 'decode': ucs2decode, + 'encode': ucs2encode + }, + 'decode': decode, + 'encode': encode, + 'toASCII': toASCII, + 'toUnicode': toUnicode +}; + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (punycode); + +/***/ }), + +/***/ 43512: +/***/ ((module) => { + +"use strict"; + + +var replace = String.prototype.replace; +var percentTwenties = /%20/g; +var Format = { + RFC1738: 'RFC1738', + RFC3986: 'RFC3986' +}; +module.exports = { + 'default': Format.RFC3986, + formatters: { + RFC1738: function (value) { + return replace.call(value, percentTwenties, '+'); + }, + RFC3986: function (value) { + return String(value); + } + }, + RFC1738: Format.RFC1738, + RFC3986: Format.RFC3986 +}; + +/***/ }), + +/***/ 349: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var stringify = __webpack_require__(74082); +var parse = __webpack_require__(48169); +var formats = __webpack_require__(43512); +module.exports = { + formats: formats, + parse: parse, + stringify: stringify +}; + +/***/ }), + +/***/ 48169: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var utils = __webpack_require__(40775); +var has = Object.prototype.hasOwnProperty; +var isArray = Array.isArray; +var defaults = { + allowDots: false, + allowPrototypes: false, + allowSparse: false, + arrayLimit: 20, + charset: 'utf-8', + charsetSentinel: false, + comma: false, + decoder: utils.decode, + delimiter: '&', + depth: 5, + ignoreQueryPrefix: false, + interpretNumericEntities: false, + parameterLimit: 1000, + parseArrays: true, + plainObjects: false, + strictNullHandling: false +}; +var interpretNumericEntities = function (str) { + return str.replace(/&#(\d+);/g, function ($0, numberStr) { + return String.fromCharCode(parseInt(numberStr, 10)); + }); +}; +var parseArrayValue = function (val, options) { + if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) { + return val.split(','); + } + return val; +}; + +// This is what browsers will submit when the ✓ character occurs in an +// application/x-www-form-urlencoded body and the encoding of the page containing +// the form is iso-8859-1, or when the submitted form has an accept-charset +// attribute of iso-8859-1. Presumably also with other charsets that do not contain +// the ✓ character, such as us-ascii. +var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓') + +// These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded. +var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓') + +var parseValues = function parseQueryStringValues(str, options) { + var obj = { + __proto__: null + }; + var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str; + var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit; + var parts = cleanStr.split(options.delimiter, limit); + var skipIndex = -1; // Keep track of where the utf8 sentinel was found + var i; + var charset = options.charset; + if (options.charsetSentinel) { + for (i = 0; i < parts.length; ++i) { + if (parts[i].indexOf('utf8=') === 0) { + if (parts[i] === charsetSentinel) { + charset = 'utf-8'; + } else if (parts[i] === isoSentinel) { + charset = 'iso-8859-1'; + } + skipIndex = i; + i = parts.length; // The eslint settings do not allow break; + } + } + } + for (i = 0; i < parts.length; ++i) { + if (i === skipIndex) { + continue; + } + var part = parts[i]; + var bracketEqualsPos = part.indexOf(']='); + var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1; + var key, val; + if (pos === -1) { + key = options.decoder(part, defaults.decoder, charset, 'key'); + val = options.strictNullHandling ? null : ''; + } else { + key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key'); + val = utils.maybeMap(parseArrayValue(part.slice(pos + 1), options), function (encodedVal) { + return options.decoder(encodedVal, defaults.decoder, charset, 'value'); + }); + } + if (val && options.interpretNumericEntities && charset === 'iso-8859-1') { + val = interpretNumericEntities(val); + } + if (part.indexOf('[]=') > -1) { + val = isArray(val) ? [val] : val; + } + if (has.call(obj, key)) { + obj[key] = utils.combine(obj[key], val); + } else { + obj[key] = val; + } + } + return obj; +}; +var parseObject = function (chain, val, options, valuesParsed) { + var leaf = valuesParsed ? val : parseArrayValue(val, options); + for (var i = chain.length - 1; i >= 0; --i) { + var obj; + var root = chain[i]; + if (root === '[]' && options.parseArrays) { + obj = [].concat(leaf); + } else { + obj = options.plainObjects ? Object.create(null) : {}; + var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root; + var index = parseInt(cleanRoot, 10); + if (!options.parseArrays && cleanRoot === '') { + obj = { + 0: leaf + }; + } else if (!isNaN(index) && root !== cleanRoot && String(index) === cleanRoot && index >= 0 && options.parseArrays && index <= options.arrayLimit) { + obj = []; + obj[index] = leaf; + } else if (cleanRoot !== '__proto__') { + obj[cleanRoot] = leaf; + } + } + leaf = obj; + } + return leaf; +}; +var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) { + if (!givenKey) { + return; + } + + // Transform dot notation to bracket notation + var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey; + + // The regex chunks + + var brackets = /(\[[^[\]]*])/; + var child = /(\[[^[\]]*])/g; + + // Get the parent + + var segment = options.depth > 0 && brackets.exec(key); + var parent = segment ? key.slice(0, segment.index) : key; + + // Stash the parent if it exists + + var keys = []; + if (parent) { + // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties + if (!options.plainObjects && has.call(Object.prototype, parent)) { + if (!options.allowPrototypes) { + return; + } + } + keys.push(parent); + } + + // Loop through children appending to the array until we hit depth + + var i = 0; + while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) { + i += 1; + if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) { + if (!options.allowPrototypes) { + return; + } + } + keys.push(segment[1]); + } + + // If there's a remainder, just add whatever is left + + if (segment) { + keys.push('[' + key.slice(segment.index) + ']'); + } + return parseObject(keys, val, options, valuesParsed); +}; +var normalizeParseOptions = function normalizeParseOptions(opts) { + if (!opts) { + return defaults; + } + if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') { + throw new TypeError('Decoder has to be a function.'); + } + if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { + throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); + } + var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset; + return { + allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots, + allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes, + allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse, + arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit, + charset: charset, + charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, + comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma, + decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder, + delimiter: typeof opts.delimiter === 'string' || utils.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter, + // eslint-disable-next-line no-implicit-coercion, no-extra-parens + depth: typeof opts.depth === 'number' || opts.depth === false ? +opts.depth : defaults.depth, + ignoreQueryPrefix: opts.ignoreQueryPrefix === true, + interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities, + parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit, + parseArrays: opts.parseArrays !== false, + plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects, + strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling + }; +}; +module.exports = function (str, opts) { + var options = normalizeParseOptions(opts); + if (str === '' || str === null || typeof str === 'undefined') { + return options.plainObjects ? Object.create(null) : {}; + } + var tempObj = typeof str === 'string' ? parseValues(str, options) : str; + var obj = options.plainObjects ? Object.create(null) : {}; + + // Iterate over the keys and setup the new object + + var keys = Object.keys(tempObj); + for (var i = 0; i < keys.length; ++i) { + var key = keys[i]; + var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string'); + obj = utils.merge(obj, newObj, options); + } + if (options.allowSparse === true) { + return obj; + } + return utils.compact(obj); +}; + +/***/ }), + +/***/ 74082: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var getSideChannel = __webpack_require__(67546); +var utils = __webpack_require__(40775); +var formats = __webpack_require__(43512); +var has = Object.prototype.hasOwnProperty; +var arrayPrefixGenerators = { + brackets: function brackets(prefix) { + return prefix + '[]'; + }, + comma: 'comma', + indices: function indices(prefix, key) { + return prefix + '[' + key + ']'; + }, + repeat: function repeat(prefix) { + return prefix; + } +}; +var isArray = Array.isArray; +var push = Array.prototype.push; +var pushToArray = function (arr, valueOrArray) { + push.apply(arr, isArray(valueOrArray) ? valueOrArray : [valueOrArray]); +}; +var toISO = Date.prototype.toISOString; +var defaultFormat = formats['default']; +var defaults = { + addQueryPrefix: false, + allowDots: false, + charset: 'utf-8', + charsetSentinel: false, + delimiter: '&', + encode: true, + encoder: utils.encode, + encodeValuesOnly: false, + format: defaultFormat, + formatter: formats.formatters[defaultFormat], + // deprecated + indices: false, + serializeDate: function serializeDate(date) { + return toISO.call(date); + }, + skipNulls: false, + strictNullHandling: false +}; +var isNonNullishPrimitive = function isNonNullishPrimitive(v) { + return typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || typeof v === 'symbol' || typeof v === 'bigint'; +}; +var sentinel = {}; +var stringify = function stringify(object, prefix, generateArrayPrefix, commaRoundTrip, strictNullHandling, skipNulls, encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, sideChannel) { + var obj = object; + var tmpSc = sideChannel; + var step = 0; + var findFlag = false; + while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) { + // Where object last appeared in the ref tree + var pos = tmpSc.get(object); + step += 1; + if (typeof pos !== 'undefined') { + if (pos === step) { + throw new RangeError('Cyclic object value'); + } else { + findFlag = true; // Break while + } + } + if (typeof tmpSc.get(sentinel) === 'undefined') { + step = 0; + } + } + if (typeof filter === 'function') { + obj = filter(prefix, obj); + } else if (obj instanceof Date) { + obj = serializeDate(obj); + } else if (generateArrayPrefix === 'comma' && isArray(obj)) { + obj = utils.maybeMap(obj, function (value) { + if (value instanceof Date) { + return serializeDate(value); + } + return value; + }); + } + if (obj === null) { + if (strictNullHandling) { + return encoder && !encodeValuesOnly ? encoder(prefix, defaults.encoder, charset, 'key', format) : prefix; + } + obj = ''; + } + if (isNonNullishPrimitive(obj) || utils.isBuffer(obj)) { + if (encoder) { + var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults.encoder, charset, 'key', format); + return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults.encoder, charset, 'value', format))]; + } + return [formatter(prefix) + '=' + formatter(String(obj))]; + } + var values = []; + if (typeof obj === 'undefined') { + return values; + } + var objKeys; + if (generateArrayPrefix === 'comma' && isArray(obj)) { + // we need to join elements in + if (encodeValuesOnly && encoder) { + obj = utils.maybeMap(obj, encoder); + } + objKeys = [{ + value: obj.length > 0 ? obj.join(',') || null : void undefined + }]; + } else if (isArray(filter)) { + objKeys = filter; + } else { + var keys = Object.keys(obj); + objKeys = sort ? keys.sort(sort) : keys; + } + var adjustedPrefix = commaRoundTrip && isArray(obj) && obj.length === 1 ? prefix + '[]' : prefix; + for (var j = 0; j < objKeys.length; ++j) { + var key = objKeys[j]; + var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key]; + if (skipNulls && value === null) { + continue; + } + var keyPrefix = isArray(obj) ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix : adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']'); + sideChannel.set(object, step); + var valueSideChannel = getSideChannel(); + valueSideChannel.set(sentinel, sideChannel); + pushToArray(values, stringify(value, keyPrefix, generateArrayPrefix, commaRoundTrip, strictNullHandling, skipNulls, generateArrayPrefix === 'comma' && encodeValuesOnly && isArray(obj) ? null : encoder, filter, sort, allowDots, serializeDate, format, formatter, encodeValuesOnly, charset, valueSideChannel)); + } + return values; +}; +var normalizeStringifyOptions = function normalizeStringifyOptions(opts) { + if (!opts) { + return defaults; + } + if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') { + throw new TypeError('Encoder has to be a function.'); + } + var charset = opts.charset || defaults.charset; + if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { + throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); + } + var format = formats['default']; + if (typeof opts.format !== 'undefined') { + if (!has.call(formats.formatters, opts.format)) { + throw new TypeError('Unknown format option provided.'); + } + format = opts.format; + } + var formatter = formats.formatters[format]; + var filter = defaults.filter; + if (typeof opts.filter === 'function' || isArray(opts.filter)) { + filter = opts.filter; + } + return { + addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults.addQueryPrefix, + allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots, + charset: charset, + charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, + delimiter: typeof opts.delimiter === 'undefined' ? defaults.delimiter : opts.delimiter, + encode: typeof opts.encode === 'boolean' ? opts.encode : defaults.encode, + encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults.encoder, + encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults.encodeValuesOnly, + filter: filter, + format: format, + formatter: formatter, + serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults.serializeDate, + skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults.skipNulls, + sort: typeof opts.sort === 'function' ? opts.sort : null, + strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling + }; +}; +module.exports = function (object, opts) { + var obj = object; + var options = normalizeStringifyOptions(opts); + var objKeys; + var filter; + if (typeof options.filter === 'function') { + filter = options.filter; + obj = filter('', obj); + } else if (isArray(options.filter)) { + filter = options.filter; + objKeys = filter; + } + var keys = []; + if (typeof obj !== 'object' || obj === null) { + return ''; + } + var arrayFormat; + if (opts && opts.arrayFormat in arrayPrefixGenerators) { + arrayFormat = opts.arrayFormat; + } else if (opts && 'indices' in opts) { + arrayFormat = opts.indices ? 'indices' : 'repeat'; + } else { + arrayFormat = 'indices'; + } + var generateArrayPrefix = arrayPrefixGenerators[arrayFormat]; + if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') { + throw new TypeError('`commaRoundTrip` must be a boolean, or absent'); + } + var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip; + if (!objKeys) { + objKeys = Object.keys(obj); + } + if (options.sort) { + objKeys.sort(options.sort); + } + var sideChannel = getSideChannel(); + for (var i = 0; i < objKeys.length; ++i) { + var key = objKeys[i]; + if (options.skipNulls && obj[key] === null) { + continue; + } + pushToArray(keys, stringify(obj[key], key, generateArrayPrefix, commaRoundTrip, options.strictNullHandling, options.skipNulls, options.encode ? options.encoder : null, options.filter, options.sort, options.allowDots, options.serializeDate, options.format, options.formatter, options.encodeValuesOnly, options.charset, sideChannel)); + } + var joined = keys.join(options.delimiter); + var prefix = options.addQueryPrefix === true ? '?' : ''; + if (options.charsetSentinel) { + if (options.charset === 'iso-8859-1') { + // encodeURIComponent('✓'), the "numeric entity" representation of a checkmark + prefix += 'utf8=%26%2310003%3B&'; + } else { + // encodeURIComponent('✓') + prefix += 'utf8=%E2%9C%93&'; + } + } + return joined.length > 0 ? prefix + joined : ''; +}; + +/***/ }), + +/***/ 40775: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var formats = __webpack_require__(43512); +var has = Object.prototype.hasOwnProperty; +var isArray = Array.isArray; +var hexTable = function () { + var array = []; + for (var i = 0; i < 256; ++i) { + array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase()); + } + return array; +}(); +var compactQueue = function compactQueue(queue) { + while (queue.length > 1) { + var item = queue.pop(); + var obj = item.obj[item.prop]; + if (isArray(obj)) { + var compacted = []; + for (var j = 0; j < obj.length; ++j) { + if (typeof obj[j] !== 'undefined') { + compacted.push(obj[j]); + } + } + item.obj[item.prop] = compacted; + } + } +}; +var arrayToObject = function arrayToObject(source, options) { + var obj = options && options.plainObjects ? Object.create(null) : {}; + for (var i = 0; i < source.length; ++i) { + if (typeof source[i] !== 'undefined') { + obj[i] = source[i]; + } + } + return obj; +}; +var merge = function merge(target, source, options) { + /* eslint no-param-reassign: 0 */ + if (!source) { + return target; + } + if (typeof source !== 'object') { + if (isArray(target)) { + target.push(source); + } else if (target && typeof target === 'object') { + if (options && (options.plainObjects || options.allowPrototypes) || !has.call(Object.prototype, source)) { + target[source] = true; + } + } else { + return [target, source]; + } + return target; + } + if (!target || typeof target !== 'object') { + return [target].concat(source); + } + var mergeTarget = target; + if (isArray(target) && !isArray(source)) { + mergeTarget = arrayToObject(target, options); + } + if (isArray(target) && isArray(source)) { + source.forEach(function (item, i) { + if (has.call(target, i)) { + var targetItem = target[i]; + if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { + target[i] = merge(targetItem, item, options); + } else { + target.push(item); + } + } else { + target[i] = item; + } + }); + return target; + } + return Object.keys(source).reduce(function (acc, key) { + var value = source[key]; + if (has.call(acc, key)) { + acc[key] = merge(acc[key], value, options); + } else { + acc[key] = value; + } + return acc; + }, mergeTarget); +}; +var assign = function assignSingleSource(target, source) { + return Object.keys(source).reduce(function (acc, key) { + acc[key] = source[key]; + return acc; + }, target); +}; +var decode = function (str, decoder, charset) { + var strWithoutPlus = str.replace(/\+/g, ' '); + if (charset === 'iso-8859-1') { + // unescape never throws, no try...catch needed: + return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape); + } + // utf-8 + try { + return decodeURIComponent(strWithoutPlus); + } catch (e) { + return strWithoutPlus; + } +}; +var encode = function encode(str, defaultEncoder, charset, kind, format) { + // This code was originally written by Brian White (mscdex) for the io.js core querystring library. + // It has been adapted here for stricter adherence to RFC 3986 + if (str.length === 0) { + return str; + } + var string = str; + if (typeof str === 'symbol') { + string = Symbol.prototype.toString.call(str); + } else if (typeof str !== 'string') { + string = String(str); + } + if (charset === 'iso-8859-1') { + return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) { + return '%26%23' + parseInt($0.slice(2), 16) + '%3B'; + }); + } + var out = ''; + for (var i = 0; i < string.length; ++i) { + var c = string.charCodeAt(i); + if (c === 0x2D // - + || c === 0x2E // . + || c === 0x5F // _ + || c === 0x7E // ~ + || c >= 0x30 && c <= 0x39 // 0-9 + || c >= 0x41 && c <= 0x5A // a-z + || c >= 0x61 && c <= 0x7A // A-Z + || format === formats.RFC1738 && (c === 0x28 || c === 0x29) // ( ) + ) { + out += string.charAt(i); + continue; + } + if (c < 0x80) { + out = out + hexTable[c]; + continue; + } + if (c < 0x800) { + out = out + (hexTable[0xC0 | c >> 6] + hexTable[0x80 | c & 0x3F]); + continue; + } + if (c < 0xD800 || c >= 0xE000) { + out = out + (hexTable[0xE0 | c >> 12] + hexTable[0x80 | c >> 6 & 0x3F] + hexTable[0x80 | c & 0x3F]); + continue; + } + i += 1; + c = 0x10000 + ((c & 0x3FF) << 10 | string.charCodeAt(i) & 0x3FF); + /* eslint operator-linebreak: [2, "before"] */ + out += hexTable[0xF0 | c >> 18] + hexTable[0x80 | c >> 12 & 0x3F] + hexTable[0x80 | c >> 6 & 0x3F] + hexTable[0x80 | c & 0x3F]; + } + return out; +}; +var compact = function compact(value) { + var queue = [{ + obj: { + o: value + }, + prop: 'o' + }]; + var refs = []; + for (var i = 0; i < queue.length; ++i) { + var item = queue[i]; + var obj = item.obj[item.prop]; + var keys = Object.keys(obj); + for (var j = 0; j < keys.length; ++j) { + var key = keys[j]; + var val = obj[key]; + if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) { + queue.push({ + obj: obj, + prop: key + }); + refs.push(val); + } + } + } + compactQueue(queue); + return value; +}; +var isRegExp = function isRegExp(obj) { + return Object.prototype.toString.call(obj) === '[object RegExp]'; +}; +var isBuffer = function isBuffer(obj) { + if (!obj || typeof obj !== 'object') { + return false; + } + return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); +}; +var combine = function combine(a, b) { + return [].concat(a, b); +}; +var maybeMap = function maybeMap(val, fn) { + if (isArray(val)) { + var mapped = []; + for (var i = 0; i < val.length; i += 1) { + mapped.push(fn(val[i])); + } + return mapped; + } + return fn(val); +}; +module.exports = { + arrayToObject: arrayToObject, + assign: assign, + combine: combine, + compact: compact, + decode: decode, + encode: encode, + isBuffer: isBuffer, + isRegExp: isRegExp, + maybeMap: maybeMap, + merge: merge +}; + +/***/ }), + +/***/ 23954: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var GetIntrinsic = __webpack_require__(55050); +var define = __webpack_require__(91037); +var hasDescriptors = __webpack_require__(96757)(); +var gOPD = __webpack_require__(12319); +var $TypeError = GetIntrinsic('%TypeError%'); +var $floor = GetIntrinsic('%Math.floor%'); +module.exports = function setFunctionLength(fn, length) { + if (typeof fn !== 'function') { + throw new $TypeError('`fn` is not a function'); + } + if (typeof length !== 'number' || length < 0 || length > 0xFFFFFFFF || $floor(length) !== length) { + throw new $TypeError('`length` must be a positive 32-bit integer'); + } + var loose = arguments.length > 2 && !!arguments[2]; + var functionLengthIsConfigurable = true; + var functionLengthIsWritable = true; + if ('length' in fn && gOPD) { + var desc = gOPD(fn, 'length'); + if (desc && !desc.configurable) { + functionLengthIsConfigurable = false; + } + if (desc && !desc.writable) { + functionLengthIsWritable = false; + } + } + if (functionLengthIsConfigurable || functionLengthIsWritable || !loose) { + if (hasDescriptors) { + define(fn, 'length', length, true, true); + } else { + define(fn, 'length', length); + } + } + return fn; +}; + +/***/ }), + +/***/ 67546: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + +"use strict"; + + +var GetIntrinsic = __webpack_require__(55050); +var callBound = __webpack_require__(3737); +var inspect = __webpack_require__(87676); +var $TypeError = GetIntrinsic('%TypeError%'); +var $WeakMap = GetIntrinsic('%WeakMap%', true); +var $Map = GetIntrinsic('%Map%', true); +var $weakMapGet = callBound('WeakMap.prototype.get', true); +var $weakMapSet = callBound('WeakMap.prototype.set', true); +var $weakMapHas = callBound('WeakMap.prototype.has', true); +var $mapGet = callBound('Map.prototype.get', true); +var $mapSet = callBound('Map.prototype.set', true); +var $mapHas = callBound('Map.prototype.has', true); + +/* + * This function traverses the list returning the node corresponding to the + * given key. + * + * That node is also moved to the head of the list, so that if it's accessed + * again we don't need to traverse the whole list. By doing so, all the recently + * used nodes can be accessed relatively quickly. + */ +var listGetNode = function (list, key) { + // eslint-disable-line consistent-return + for (var prev = list, curr; (curr = prev.next) !== null; prev = curr) { + if (curr.key === key) { + prev.next = curr.next; + curr.next = list.next; + list.next = curr; // eslint-disable-line no-param-reassign + return curr; + } + } +}; +var listGet = function (objects, key) { + var node = listGetNode(objects, key); + return node && node.value; +}; +var listSet = function (objects, key, value) { + var node = listGetNode(objects, key); + if (node) { + node.value = value; + } else { + // Prepend the new node to the beginning of the list + objects.next = { + // eslint-disable-line no-param-reassign + key: key, + next: objects.next, + value: value + }; + } +}; +var listHas = function (objects, key) { + return !!listGetNode(objects, key); +}; +module.exports = function getSideChannel() { + var $wm; + var $m; + var $o; + var channel = { + assert: function (key) { + if (!channel.has(key)) { + throw new $TypeError('Side channel does not contain ' + inspect(key)); + } + }, + get: function (key) { + // eslint-disable-line consistent-return + if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { + if ($wm) { + return $weakMapGet($wm, key); + } + } else if ($Map) { + if ($m) { + return $mapGet($m, key); + } + } else { + if ($o) { + // eslint-disable-line no-lonely-if + return listGet($o, key); + } + } + }, + has: function (key) { + if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { + if ($wm) { + return $weakMapHas($wm, key); + } + } else if ($Map) { + if ($m) { + return $mapHas($m, key); + } + } else { + if ($o) { + // eslint-disable-line no-lonely-if + return listHas($o, key); + } + } + return false; + }, + set: function (key, value) { + if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { + if (!$wm) { + $wm = new $WeakMap(); + } + $weakMapSet($wm, key, value); + } else if ($Map) { + if (!$m) { + $m = new $Map(); + } + $mapSet($m, key, value); + } else { + if (!$o) { + /* + * Initialize the linked list as an empty node, so that we don't have + * to special-case handling of the first node: we can always refer to + * it as (previous node).next, instead of something like (list).head + */ + $o = { + key: {}, + next: null + }; + } + listSet($o, key, value); + } + } + }; + return channel; +}; + +/***/ }), + +/***/ 69573: +/***/ ((__unused_webpack_module, exports, __webpack_require__) => { + +"use strict"; +/* + * Copyright Joyent, Inc. and other Node contributors. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do so, subject to the + * following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + + +var punycode = __webpack_require__(43277); +function Url() { + this.protocol = null; + this.slashes = null; + this.auth = null; + this.host = null; + this.port = null; + this.hostname = null; + this.hash = null; + this.search = null; + this.query = null; + this.pathname = null; + this.path = null; + this.href = null; +} + +// Reference: RFC 3986, RFC 1808, RFC 2396 + +/* + * define these here so at least they only have to be + * compiled once on the first module load. + */ +var protocolPattern = /^([a-z0-9.+-]+:)/i, + portPattern = /:[0-9]*$/, + // Special case for a simple path URL + simplePathPattern = /^(\/\/?(?!\/)[^?\s]*)(\?[^\s]*)?$/, + /* + * RFC 2396: characters reserved for delimiting URLs. + * We actually just auto-escape these. + */ + delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'], + // RFC 2396: characters not allowed for various reasons. + unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims), + // Allowed by RFCs, but cause of XSS attacks. Always escape these. + autoEscape = ['\''].concat(unwise), + /* + * Characters that are never ever allowed in a hostname. + * Note that any invalid chars are also handled, but these + * are the ones that are *expected* to be seen, so we fast-path + * them. + */ + nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape), + hostEndingChars = ['/', '?', '#'], + hostnameMaxLen = 255, + hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/, + hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/, + // protocols that can allow "unsafe" and "unwise" chars. + unsafeProtocol = { + javascript: true, + 'javascript:': true + }, + // protocols that never have a hostname. + hostlessProtocol = { + javascript: true, + 'javascript:': true + }, + // protocols that always contain a // bit. + slashedProtocol = { + http: true, + https: true, + ftp: true, + gopher: true, + file: true, + 'http:': true, + 'https:': true, + 'ftp:': true, + 'gopher:': true, + 'file:': true + }, + querystring = __webpack_require__(349); +function urlParse(url, parseQueryString, slashesDenoteHost) { + if (url && typeof url === 'object' && url instanceof Url) { + return url; + } + var u = new Url(); + u.parse(url, parseQueryString, slashesDenoteHost); + return u; +} +Url.prototype.parse = function (url, parseQueryString, slashesDenoteHost) { + if (typeof url !== 'string') { + throw new TypeError("Parameter 'url' must be a string, not " + typeof url); + } + + /* + * Copy chrome, IE, opera backslash-handling behavior. + * Back slashes before the query string get converted to forward slashes + * See: https://code.google.com/p/chromium/issues/detail?id=25916 + */ + var queryIndex = url.indexOf('?'), + splitter = queryIndex !== -1 && queryIndex < url.indexOf('#') ? '?' : '#', + uSplit = url.split(splitter), + slashRegex = /\\/g; + uSplit[0] = uSplit[0].replace(slashRegex, '/'); + url = uSplit.join(splitter); + var rest = url; + + /* + * trim before proceeding. + * This is to support parse stuff like " http://foo.com \n" + */ + rest = rest.trim(); + if (!slashesDenoteHost && url.split('#').length === 1) { + // Try fast path regexp + var simplePath = simplePathPattern.exec(rest); + if (simplePath) { + this.path = rest; + this.href = rest; + this.pathname = simplePath[1]; + if (simplePath[2]) { + this.search = simplePath[2]; + if (parseQueryString) { + this.query = querystring.parse(this.search.substr(1)); + } else { + this.query = this.search.substr(1); + } + } else if (parseQueryString) { + this.search = ''; + this.query = {}; + } + return this; + } + } + var proto = protocolPattern.exec(rest); + if (proto) { + proto = proto[0]; + var lowerProto = proto.toLowerCase(); + this.protocol = lowerProto; + rest = rest.substr(proto.length); + } + + /* + * figure out if it's got a host + * user@server is *always* interpreted as a hostname, and url + * resolution will treat //foo/bar as host=foo,path=bar because that's + * how the browser resolves relative URLs. + */ + if (slashesDenoteHost || proto || rest.match(/^\/\/[^@/]+@[^@/]+/)) { + var slashes = rest.substr(0, 2) === '//'; + if (slashes && !(proto && hostlessProtocol[proto])) { + rest = rest.substr(2); + this.slashes = true; + } + } + if (!hostlessProtocol[proto] && (slashes || proto && !slashedProtocol[proto])) { + /* + * there's a hostname. + * the first instance of /, ?, ;, or # ends the host. + * + * If there is an @ in the hostname, then non-host chars *are* allowed + * to the left of the last @ sign, unless some host-ending character + * comes *before* the @-sign. + * URLs are obnoxious. + * + * ex: + * http://a@b@c/ => user:a@b host:c + * http://a@b?@c => user:a host:c path:/?@c + */ + + /* + * v0.12 TODO(isaacs): This is not quite how Chrome does things. + * Review our test case against browsers more comprehensively. + */ + + // find the first instance of any hostEndingChars + var hostEnd = -1; + for (var i = 0; i < hostEndingChars.length; i++) { + var hec = rest.indexOf(hostEndingChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) { + hostEnd = hec; + } + } + + /* + * at this point, either we have an explicit point where the + * auth portion cannot go past, or the last @ char is the decider. + */ + var auth, atSign; + if (hostEnd === -1) { + // atSign can be anywhere. + atSign = rest.lastIndexOf('@'); + } else { + /* + * atSign must be in auth portion. + * http://a@b/c@d => host:b auth:a path:/c@d + */ + atSign = rest.lastIndexOf('@', hostEnd); + } + + /* + * Now we have a portion which is definitely the auth. + * Pull that off. + */ + if (atSign !== -1) { + auth = rest.slice(0, atSign); + rest = rest.slice(atSign + 1); + this.auth = decodeURIComponent(auth); + } + + // the host is the remaining to the left of the first non-host char + hostEnd = -1; + for (var i = 0; i < nonHostChars.length; i++) { + var hec = rest.indexOf(nonHostChars[i]); + if (hec !== -1 && (hostEnd === -1 || hec < hostEnd)) { + hostEnd = hec; + } + } + // if we still have not hit it, then the entire thing is a host. + if (hostEnd === -1) { + hostEnd = rest.length; + } + this.host = rest.slice(0, hostEnd); + rest = rest.slice(hostEnd); + + // pull out port. + this.parseHost(); + + /* + * we've indicated that there is a hostname, + * so even if it's empty, it has to be present. + */ + this.hostname = this.hostname || ''; + + /* + * if hostname begins with [ and ends with ] + * assume that it's an IPv6 address. + */ + var ipv6Hostname = this.hostname[0] === '[' && this.hostname[this.hostname.length - 1] === ']'; + + // validate a little. + if (!ipv6Hostname) { + var hostparts = this.hostname.split(/\./); + for (var i = 0, l = hostparts.length; i < l; i++) { + var part = hostparts[i]; + if (!part) { + continue; + } + if (!part.match(hostnamePartPattern)) { + var newpart = ''; + for (var j = 0, k = part.length; j < k; j++) { + if (part.charCodeAt(j) > 127) { + /* + * we replace non-ASCII char with a temporary placeholder + * we need this to make sure size of hostname is not + * broken by replacing non-ASCII by nothing + */ + newpart += 'x'; + } else { + newpart += part[j]; + } + } + // we test again with ASCII char only + if (!newpart.match(hostnamePartPattern)) { + var validParts = hostparts.slice(0, i); + var notHost = hostparts.slice(i + 1); + var bit = part.match(hostnamePartStart); + if (bit) { + validParts.push(bit[1]); + notHost.unshift(bit[2]); + } + if (notHost.length) { + rest = '/' + notHost.join('.') + rest; + } + this.hostname = validParts.join('.'); + break; + } + } + } + } + if (this.hostname.length > hostnameMaxLen) { + this.hostname = ''; + } else { + // hostnames are always lower case. + this.hostname = this.hostname.toLowerCase(); + } + if (!ipv6Hostname) { + /* + * IDNA Support: Returns a punycoded representation of "domain". + * It only converts parts of the domain name that + * have non-ASCII characters, i.e. it doesn't matter if + * you call it with a domain that already is ASCII-only. + */ + this.hostname = punycode.toASCII(this.hostname); + } + var p = this.port ? ':' + this.port : ''; + var h = this.hostname || ''; + this.host = h + p; + this.href += this.host; + + /* + * strip [ and ] from the hostname + * the host field still retains them, though + */ + if (ipv6Hostname) { + this.hostname = this.hostname.substr(1, this.hostname.length - 2); + if (rest[0] !== '/') { + rest = '/' + rest; + } + } + } + + /* + * now rest is set to the post-host stuff. + * chop off any delim chars. + */ + if (!unsafeProtocol[lowerProto]) { + /* + * First, make 100% sure that any "autoEscape" chars get + * escaped, even if encodeURIComponent doesn't think they + * need to be. + */ + for (var i = 0, l = autoEscape.length; i < l; i++) { + var ae = autoEscape[i]; + if (rest.indexOf(ae) === -1) { + continue; + } + var esc = encodeURIComponent(ae); + if (esc === ae) { + esc = escape(ae); + } + rest = rest.split(ae).join(esc); + } + } + + // chop off from the tail first. + var hash = rest.indexOf('#'); + if (hash !== -1) { + // got a fragment string. + this.hash = rest.substr(hash); + rest = rest.slice(0, hash); + } + var qm = rest.indexOf('?'); + if (qm !== -1) { + this.search = rest.substr(qm); + this.query = rest.substr(qm + 1); + if (parseQueryString) { + this.query = querystring.parse(this.query); + } + rest = rest.slice(0, qm); + } else if (parseQueryString) { + // no query string, but parseQueryString still requested + this.search = ''; + this.query = {}; + } + if (rest) { + this.pathname = rest; + } + if (slashedProtocol[lowerProto] && this.hostname && !this.pathname) { + this.pathname = '/'; + } + + // to support http.request + if (this.pathname || this.search) { + var p = this.pathname || ''; + var s = this.search || ''; + this.path = p + s; + } + + // finally, reconstruct the href based on what has been validated. + this.href = this.format(); + return this; +}; + +// format a parsed object into a url string +function urlFormat(obj) { + /* + * ensure it's an object, and not a string url. + * If it's an obj, this is a no-op. + * this way, you can call url_format() on strings + * to clean up potentially wonky urls. + */ + if (typeof obj === 'string') { + obj = urlParse(obj); + } + if (!(obj instanceof Url)) { + return Url.prototype.format.call(obj); + } + return obj.format(); +} +Url.prototype.format = function () { + var auth = this.auth || ''; + if (auth) { + auth = encodeURIComponent(auth); + auth = auth.replace(/%3A/i, ':'); + auth += '@'; + } + var protocol = this.protocol || '', + pathname = this.pathname || '', + hash = this.hash || '', + host = false, + query = ''; + if (this.host) { + host = auth + this.host; + } else if (this.hostname) { + host = auth + (this.hostname.indexOf(':') === -1 ? this.hostname : '[' + this.hostname + ']'); + if (this.port) { + host += ':' + this.port; + } + } + if (this.query && typeof this.query === 'object' && Object.keys(this.query).length) { + query = querystring.stringify(this.query, { + arrayFormat: 'repeat', + addQueryPrefix: false + }); + } + var search = this.search || query && '?' + query || ''; + if (protocol && protocol.substr(-1) !== ':') { + protocol += ':'; + } + + /* + * only the slashedProtocols get the //. Not mailto:, xmpp:, etc. + * unless they had them to begin with. + */ + if (this.slashes || (!protocol || slashedProtocol[protocol]) && host !== false) { + host = '//' + (host || ''); + if (pathname && pathname.charAt(0) !== '/') { + pathname = '/' + pathname; + } + } else if (!host) { + host = ''; + } + if (hash && hash.charAt(0) !== '#') { + hash = '#' + hash; + } + if (search && search.charAt(0) !== '?') { + search = '?' + search; + } + pathname = pathname.replace(/[?#]/g, function (match) { + return encodeURIComponent(match); + }); + search = search.replace('#', '%23'); + return protocol + host + pathname + search + hash; +}; +function urlResolve(source, relative) { + return urlParse(source, false, true).resolve(relative); +} +Url.prototype.resolve = function (relative) { + return this.resolveObject(urlParse(relative, false, true)).format(); +}; +function urlResolveObject(source, relative) { + if (!source) { + return relative; + } + return urlParse(source, false, true).resolveObject(relative); +} +Url.prototype.resolveObject = function (relative) { + if (typeof relative === 'string') { + var rel = new Url(); + rel.parse(relative, false, true); + relative = rel; + } + var result = new Url(); + var tkeys = Object.keys(this); + for (var tk = 0; tk < tkeys.length; tk++) { + var tkey = tkeys[tk]; + result[tkey] = this[tkey]; + } + + /* + * hash is always overridden, no matter what. + * even href="" will remove it. + */ + result.hash = relative.hash; + + // if the relative url is empty, then there's nothing left to do here. + if (relative.href === '') { + result.href = result.format(); + return result; + } + + // hrefs like //foo/bar always cut to the protocol. + if (relative.slashes && !relative.protocol) { + // take everything except the protocol from relative + var rkeys = Object.keys(relative); + for (var rk = 0; rk < rkeys.length; rk++) { + var rkey = rkeys[rk]; + if (rkey !== 'protocol') { + result[rkey] = relative[rkey]; + } + } + + // urlParse appends trailing / to urls like http://www.example.com + if (slashedProtocol[result.protocol] && result.hostname && !result.pathname) { + result.pathname = '/'; + result.path = result.pathname; + } + result.href = result.format(); + return result; + } + if (relative.protocol && relative.protocol !== result.protocol) { + /* + * if it's a known url protocol, then changing + * the protocol does weird things + * first, if it's not file:, then we MUST have a host, + * and if there was a path + * to begin with, then we MUST have a path. + * if it is file:, then the host is dropped, + * because that's known to be hostless. + * anything else is assumed to be absolute. + */ + if (!slashedProtocol[relative.protocol]) { + var keys = Object.keys(relative); + for (var v = 0; v < keys.length; v++) { + var k = keys[v]; + result[k] = relative[k]; + } + result.href = result.format(); + return result; + } + result.protocol = relative.protocol; + if (!relative.host && !hostlessProtocol[relative.protocol]) { + var relPath = (relative.pathname || '').split('/'); + while (relPath.length && !(relative.host = relPath.shift())) {} + if (!relative.host) { + relative.host = ''; + } + if (!relative.hostname) { + relative.hostname = ''; + } + if (relPath[0] !== '') { + relPath.unshift(''); + } + if (relPath.length < 2) { + relPath.unshift(''); + } + result.pathname = relPath.join('/'); + } else { + result.pathname = relative.pathname; + } + result.search = relative.search; + result.query = relative.query; + result.host = relative.host || ''; + result.auth = relative.auth; + result.hostname = relative.hostname || relative.host; + result.port = relative.port; + // to support http.request + if (result.pathname || result.search) { + var p = result.pathname || ''; + var s = result.search || ''; + result.path = p + s; + } + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; + } + var isSourceAbs = result.pathname && result.pathname.charAt(0) === '/', + isRelAbs = relative.host || relative.pathname && relative.pathname.charAt(0) === '/', + mustEndAbs = isRelAbs || isSourceAbs || result.host && relative.pathname, + removeAllDots = mustEndAbs, + srcPath = result.pathname && result.pathname.split('/') || [], + relPath = relative.pathname && relative.pathname.split('/') || [], + psychotic = result.protocol && !slashedProtocol[result.protocol]; + + /* + * if the url is a non-slashed url, then relative + * links like ../.. should be able + * to crawl up to the hostname, as well. This is strange. + * result.protocol has already been set by now. + * Later on, put the first path part into the host field. + */ + if (psychotic) { + result.hostname = ''; + result.port = null; + if (result.host) { + if (srcPath[0] === '') { + srcPath[0] = result.host; + } else { + srcPath.unshift(result.host); + } + } + result.host = ''; + if (relative.protocol) { + relative.hostname = null; + relative.port = null; + if (relative.host) { + if (relPath[0] === '') { + relPath[0] = relative.host; + } else { + relPath.unshift(relative.host); + } + } + relative.host = null; + } + mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === ''); + } + if (isRelAbs) { + // it's absolute. + result.host = relative.host || relative.host === '' ? relative.host : result.host; + result.hostname = relative.hostname || relative.hostname === '' ? relative.hostname : result.hostname; + result.search = relative.search; + result.query = relative.query; + srcPath = relPath; + // fall through to the dot-handling below. + } else if (relPath.length) { + /* + * it's relative + * throw away the existing file, and take the new path instead. + */ + if (!srcPath) { + srcPath = []; + } + srcPath.pop(); + srcPath = srcPath.concat(relPath); + result.search = relative.search; + result.query = relative.query; + } else if (relative.search != null) { + /* + * just pull out the search. + * like href='?foo'. + * Put this after the other two cases because it simplifies the booleans + */ + if (psychotic) { + result.host = srcPath.shift(); + result.hostname = result.host; + /* + * occationaly the auth can get stuck only in host + * this especially happens in cases like + * url.resolveObject('mailto:local1@domain1', 'local2@domain2') + */ + var authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.hostname = authInHost.shift(); + result.host = result.hostname; + } + } + result.search = relative.search; + result.query = relative.query; + // to support http.request + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); + } + result.href = result.format(); + return result; + } + if (!srcPath.length) { + /* + * no path at all. easy. + * we've already handled the other stuff above. + */ + result.pathname = null; + // to support http.request + if (result.search) { + result.path = '/' + result.search; + } else { + result.path = null; + } + result.href = result.format(); + return result; + } + + /* + * if a url ENDs in . or .., then it must get a trailing slash. + * however, if it ends in anything else non-slashy, + * then it must NOT get a trailing slash. + */ + var last = srcPath.slice(-1)[0]; + var hasTrailingSlash = (result.host || relative.host || srcPath.length > 1) && (last === '.' || last === '..') || last === ''; + + /* + * strip single dots, resolve double dots to parent dir + * if the path tries to go above the root, `up` ends up > 0 + */ + var up = 0; + for (var i = srcPath.length; i >= 0; i--) { + last = srcPath[i]; + if (last === '.') { + srcPath.splice(i, 1); + } else if (last === '..') { + srcPath.splice(i, 1); + up++; + } else if (up) { + srcPath.splice(i, 1); + up--; + } + } + + // if the path is allowed to go above the root, restore leading ..s + if (!mustEndAbs && !removeAllDots) { + for (; up--; up) { + srcPath.unshift('..'); + } + } + if (mustEndAbs && srcPath[0] !== '' && (!srcPath[0] || srcPath[0].charAt(0) !== '/')) { + srcPath.unshift(''); + } + if (hasTrailingSlash && srcPath.join('/').substr(-1) !== '/') { + srcPath.push(''); + } + var isAbsolute = srcPath[0] === '' || srcPath[0] && srcPath[0].charAt(0) === '/'; + + // put the host back + if (psychotic) { + result.hostname = isAbsolute ? '' : srcPath.length ? srcPath.shift() : ''; + result.host = result.hostname; + /* + * occationaly the auth can get stuck only in host + * this especially happens in cases like + * url.resolveObject('mailto:local1@domain1', 'local2@domain2') + */ + var authInHost = result.host && result.host.indexOf('@') > 0 ? result.host.split('@') : false; + if (authInHost) { + result.auth = authInHost.shift(); + result.hostname = authInHost.shift(); + result.host = result.hostname; + } + } + mustEndAbs = mustEndAbs || result.host && srcPath.length; + if (mustEndAbs && !isAbsolute) { + srcPath.unshift(''); + } + if (srcPath.length > 0) { + result.pathname = srcPath.join('/'); + } else { + result.pathname = null; + result.path = null; + } + + // to support request.http + if (result.pathname !== null || result.search !== null) { + result.path = (result.pathname ? result.pathname : '') + (result.search ? result.search : ''); + } + result.auth = relative.auth || result.auth; + result.slashes = result.slashes || relative.slashes; + result.href = result.format(); + return result; +}; +Url.prototype.parseHost = function () { + var host = this.host; + var port = portPattern.exec(host); + if (port) { + port = port[0]; + if (port !== ':') { + this.port = port.substr(1); + } + host = host.substr(0, host.length - port.length); + } + if (host) { + this.hostname = host; + } +}; +exports.parse = urlParse; +exports.resolve = urlResolve; +exports.resolveObject = urlResolveObject; +exports.format = urlFormat; +exports.Url = Url; + +/***/ }), + +/***/ 53260: +/***/ (() => { + +/* (ignored) */ + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/global */ +/******/ (() => { +/******/ __webpack_require__.g = (function() { +/******/ if (typeof globalThis === 'object') return globalThis; +/******/ try { +/******/ return this || new Function('return this')(); +/******/ } catch (e) { +/******/ if (typeof window === 'object') return window; +/******/ } +/******/ })(); +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; + +;// CONCATENATED MODULE: ../../libs/common/src/vault/abstractions/fido2/fido2-client.service.abstraction.ts +const UserRequestedFallbackAbortReason = "UserRequestedFallback"; +/** + * This class represents an abstraction of the WebAuthn Client as described by W3C: + * https://www.w3.org/TR/webauthn-3/#webauthn-client + * + * The WebAuthn Client is an intermediary entity typically implemented in the user agent + * (in whole, or in part). Conceptually, it underlies the Web Authentication API and embodies + * the implementation of the Web Authentication API's operations. + * + * It is responsible for both marshalling the inputs for the underlying authenticator operations, + * and for returning the results of the latter operations to the Web Authentication API's callers. + */ +class Fido2ClientService { +} +/** + * Error thrown when the user requests a fallback to the browser's built-in WebAuthn implementation. + */ +class FallbackRequestedError extends Error { + constructor() { + super("FallbackRequested"); + this.fallbackRequested = true; + } +} + +// EXTERNAL MODULE: ../../node_modules/path-browserify/index.js +var path_browserify = __webpack_require__(14375); +// EXTERNAL MODULE: ../../node_modules/buffer/index.js +var node_modules_buffer = __webpack_require__(7312); +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isFunction.js +function isFunction_isFunction(value) { + return typeof value === 'function'; +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isScheduler.js + +function isScheduler(value) { + return value && isFunction_isFunction(value.schedule); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/args.js + + +function last(arr) { + return arr[arr.length - 1]; +} +function popResultSelector(args) { + return isFunction(last(args)) ? args.pop() : undefined; +} +function popScheduler(args) { + return isScheduler(last(args)) ? args.pop() : undefined; +} +function popNumber(args, defaultValue) { + return typeof last(args) === 'number' ? args.pop() : defaultValue; +} +;// CONCATENATED MODULE: ../../node_modules/tslib/tslib.es6.mjs +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise, SuppressedError, Symbol */ + +var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || { + __proto__: [] + } instanceof Array && function (d, b) { + d.__proto__ = b; + } || function (d, b) { + for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; + }; + return extendStatics(d, b); +}; +function __extends(d, b) { + if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { + this.constructor = d; + } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} +var __assign = function () { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; + } + return t; +} +function __decorate(decorators, target, key, desc) { + var c = arguments.length, + r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, + d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} +function __param(paramIndex, decorator) { + return function (target, key) { + decorator(target, key, paramIndex); + }; +} +function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { + if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); + return f; + } + var kind = contextIn.kind, + key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, + done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { + if (done) throw new TypeError("Cannot add initializers after decoration has completed"); + extraInitializers.push(accept(f || null)); + }; + var result = (0, decorators[i])(kind === "accessor" ? { + get: descriptor.get, + set: descriptor.set + } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_);else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +} +; +function __runInitializers(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +} +; +function __propKey(x) { + return typeof x === "symbol" ? x : "".concat(x); +} +; +function __setFunctionName(f, name, prefix) { + if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; + return Object.defineProperty(f, "name", { + configurable: true, + value: prefix ? "".concat(prefix, " ", name) : name + }); +} +; +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { + return value instanceof P ? value : new P(function (resolve) { + resolve(value); + }); + } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { + try { + step(generator.next(value)); + } catch (e) { + reject(e); + } + } + function rejected(value) { + try { + step(generator["throw"](value)); + } catch (e) { + reject(e); + } + } + function step(result) { + result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); + } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} +function __generator(thisArg, body) { + var _ = { + label: 0, + sent: function () { + if (t[0] & 1) throw t[1]; + return t[1]; + }, + trys: [], + ops: [] + }, + f, + y, + t, + g; + return g = { + next: verb(0), + "throw": verb(1), + "return": verb(2) + }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { + return this; + }), g; + function verb(n) { + return function (v) { + return step([n, v]); + }; + } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: + case 1: + t = op; + break; + case 4: + _.label++; + return { + value: op[1], + done: false + }; + case 5: + _.label++; + y = op[1]; + op = [0]; + continue; + case 7: + op = _.ops.pop(); + _.trys.pop(); + continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { + _ = 0; + continue; + } + if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) { + _.label = op[1]; + break; + } + if (op[0] === 6 && _.label < t[1]) { + _.label = t[1]; + t = op; + break; + } + if (t && _.label < t[2]) { + _.label = t[2]; + _.ops.push(op); + break; + } + if (t[2]) _.ops.pop(); + _.trys.pop(); + continue; + } + op = body.call(thisArg, _); + } catch (e) { + op = [6, e]; + y = 0; + } finally { + f = t = 0; + } + if (op[0] & 5) throw op[1]; + return { + value: op[0] ? op[1] : void 0, + done: true + }; + } +} +var __createBinding = Object.create ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { + enumerable: true, + get: function () { + return m[k]; + } + }; + } + Object.defineProperty(o, k2, desc); +} : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +}; +function __exportStar(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); +} +function __values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, + m = s && o[s], + i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { + value: o && o[i++], + done: !o + }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), + r, + ar = [], + e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } catch (error) { + e = { + error: error + }; + } finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } finally { + if (e) throw e.error; + } + } + return ar; +} + +/** @deprecated */ +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); + return ar; +} + +/** @deprecated */ +function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; + return r; +} +function __spreadArray(to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +} +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), + i, + q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { + return this; + }, i; + function verb(n) { + if (g[n]) i[n] = function (v) { + return new Promise(function (a, b) { + q.push([n, v, a, b]) > 1 || resume(n, v); + }); + }; + } + function resume(n, v) { + try { + step(g[n](v)); + } catch (e) { + settle(q[0][3], e); + } + } + function step(r) { + r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); + } + function fulfill(value) { + resume("next", value); + } + function reject(value) { + resume("throw", value); + } + function settle(f, v) { + if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); + } +} +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { + throw e; + }), verb("return"), i[Symbol.iterator] = function () { + return this; + }, i; + function verb(n, f) { + i[n] = o[n] ? function (v) { + return (p = !p) ? { + value: __await(o[n](v)), + done: false + } : f ? f(v) : v; + } : f; + } +} +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], + i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { + return this; + }, i); + function verb(n) { + i[n] = o[n] && function (v) { + return new Promise(function (resolve, reject) { + v = o[n](v), settle(resolve, reject, v.done, v.value); + }); + }; + } + function settle(resolve, reject, d, v) { + Promise.resolve(v).then(function (v) { + resolve({ + value: v, + done: d + }); + }, reject); + } +} +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { + Object.defineProperty(cooked, "raw", { + value: raw + }); + } else { + cooked.raw = raw; + } + return cooked; +} +; +var __setModuleDefault = Object.create ? function (o, v) { + Object.defineProperty(o, "default", { + enumerable: true, + value: v + }); +} : function (o, v) { + o["default"] = v; +}; +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +} +function __importDefault(mod) { + return mod && mod.__esModule ? mod : { + default: mod + }; +} +function __classPrivateFieldGet(receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +} +function __classPrivateFieldSet(receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value; +} +function __classPrivateFieldIn(state, receiver) { + if (receiver === null || typeof receiver !== "object" && typeof receiver !== "function") throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); +} +function __addDisposableResource(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + env.stack.push({ + value: value, + dispose: dispose, + async: async + }); + } else if (async) { + env.stack.push({ + async: true + }); + } + return value; +} +var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; +function __disposeResources(env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + function next() { + while (env.stack.length) { + var rec = env.stack.pop(); + try { + var result = rec.dispose && rec.dispose.call(rec.value); + if (rec.async) return Promise.resolve(result).then(next, function (e) { + fail(e); + return next(); + }); + } catch (e) { + fail(e); + } + } + if (env.hasError) throw env.error; + } + return next(); +} +/* harmony default export */ const tslib_es6 = ({ + __extends, + __assign, + __rest, + __decorate, + __param, + __metadata, + __awaiter, + __generator, + __createBinding, + __exportStar, + __values, + __read, + __spread, + __spreadArrays, + __spreadArray, + __await, + __asyncGenerator, + __asyncDelegator, + __asyncValues, + __makeTemplateObject, + __importStar, + __importDefault, + __classPrivateFieldGet, + __classPrivateFieldSet, + __classPrivateFieldIn, + __addDisposableResource, + __disposeResources +}); +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isArrayLike.js +var isArrayLike = function (x) { + return x && typeof x.length === 'number' && typeof x !== 'function'; +}; +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isPromise.js + +function isPromise(value) { + return isFunction_isFunction(value === null || value === void 0 ? void 0 : value.then); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/createErrorClass.js +function createErrorClass(createImpl) { + var _super = function (instance) { + Error.call(instance); + instance.stack = new Error().stack; + }; + var ctorFunc = createImpl(_super); + ctorFunc.prototype = Object.create(Error.prototype); + ctorFunc.prototype.constructor = ctorFunc; + return ctorFunc; +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/UnsubscriptionError.js + +var UnsubscriptionError = createErrorClass(function (_super) { + return function UnsubscriptionErrorImpl(errors) { + _super(this); + this.message = errors ? errors.length + " errors occurred during unsubscription:\n" + errors.map(function (err, i) { + return i + 1 + ") " + err.toString(); + }).join('\n ') : ''; + this.name = 'UnsubscriptionError'; + this.errors = errors; + }; +}); +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/arrRemove.js +function arrRemove(arr, item) { + if (arr) { + var index = arr.indexOf(item); + 0 <= index && arr.splice(index, 1); + } +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/Subscription.js + + + + +var Subscription = function () { + function Subscription(initialTeardown) { + this.initialTeardown = initialTeardown; + this.closed = false; + this._parentage = null; + this._finalizers = null; + } + Subscription.prototype.unsubscribe = function () { + var e_1, _a, e_2, _b; + var errors; + if (!this.closed) { + this.closed = true; + var _parentage = this._parentage; + if (_parentage) { + this._parentage = null; + if (Array.isArray(_parentage)) { + try { + for (var _parentage_1 = __values(_parentage), _parentage_1_1 = _parentage_1.next(); !_parentage_1_1.done; _parentage_1_1 = _parentage_1.next()) { + var parent_1 = _parentage_1_1.value; + parent_1.remove(this); + } + } catch (e_1_1) { + e_1 = { + error: e_1_1 + }; + } finally { + try { + if (_parentage_1_1 && !_parentage_1_1.done && (_a = _parentage_1.return)) _a.call(_parentage_1); + } finally { + if (e_1) throw e_1.error; + } + } + } else { + _parentage.remove(this); + } + } + var initialFinalizer = this.initialTeardown; + if (isFunction_isFunction(initialFinalizer)) { + try { + initialFinalizer(); + } catch (e) { + errors = e instanceof UnsubscriptionError ? e.errors : [e]; + } + } + var _finalizers = this._finalizers; + if (_finalizers) { + this._finalizers = null; + try { + for (var _finalizers_1 = __values(_finalizers), _finalizers_1_1 = _finalizers_1.next(); !_finalizers_1_1.done; _finalizers_1_1 = _finalizers_1.next()) { + var finalizer = _finalizers_1_1.value; + try { + execFinalizer(finalizer); + } catch (err) { + errors = errors !== null && errors !== void 0 ? errors : []; + if (err instanceof UnsubscriptionError) { + errors = __spreadArray(__spreadArray([], __read(errors)), __read(err.errors)); + } else { + errors.push(err); + } + } + } + } catch (e_2_1) { + e_2 = { + error: e_2_1 + }; + } finally { + try { + if (_finalizers_1_1 && !_finalizers_1_1.done && (_b = _finalizers_1.return)) _b.call(_finalizers_1); + } finally { + if (e_2) throw e_2.error; + } + } + } + if (errors) { + throw new UnsubscriptionError(errors); + } + } + }; + Subscription.prototype.add = function (teardown) { + var _a; + if (teardown && teardown !== this) { + if (this.closed) { + execFinalizer(teardown); + } else { + if (teardown instanceof Subscription) { + if (teardown.closed || teardown._hasParent(this)) { + return; + } + teardown._addParent(this); + } + (this._finalizers = (_a = this._finalizers) !== null && _a !== void 0 ? _a : []).push(teardown); + } + } + }; + Subscription.prototype._hasParent = function (parent) { + var _parentage = this._parentage; + return _parentage === parent || Array.isArray(_parentage) && _parentage.includes(parent); + }; + Subscription.prototype._addParent = function (parent) { + var _parentage = this._parentage; + this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent; + }; + Subscription.prototype._removeParent = function (parent) { + var _parentage = this._parentage; + if (_parentage === parent) { + this._parentage = null; + } else if (Array.isArray(_parentage)) { + arrRemove(_parentage, parent); + } + }; + Subscription.prototype.remove = function (teardown) { + var _finalizers = this._finalizers; + _finalizers && arrRemove(_finalizers, teardown); + if (teardown instanceof Subscription) { + teardown._removeParent(this); + } + }; + Subscription.EMPTY = function () { + var empty = new Subscription(); + empty.closed = true; + return empty; + }(); + return Subscription; +}(); + +var EMPTY_SUBSCRIPTION = Subscription.EMPTY; +function isSubscription(value) { + return value instanceof Subscription || value && 'closed' in value && isFunction_isFunction(value.remove) && isFunction_isFunction(value.add) && isFunction_isFunction(value.unsubscribe); +} +function execFinalizer(finalizer) { + if (isFunction_isFunction(finalizer)) { + finalizer(); + } else { + finalizer.unsubscribe(); + } +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/config.js +var config = { + onUnhandledError: null, + onStoppedNotification: null, + Promise: undefined, + useDeprecatedSynchronousErrorHandling: false, + useDeprecatedNextContext: false +}; +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduler/timeoutProvider.js + +var timeoutProvider = { + setTimeout: function (handler, timeout) { + var args = []; + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + var delegate = timeoutProvider.delegate; + if (delegate === null || delegate === void 0 ? void 0 : delegate.setTimeout) { + return delegate.setTimeout.apply(delegate, __spreadArray([handler, timeout], __read(args))); + } + return setTimeout.apply(void 0, __spreadArray([handler, timeout], __read(args))); + }, + clearTimeout: function (handle) { + var delegate = timeoutProvider.delegate; + return ((delegate === null || delegate === void 0 ? void 0 : delegate.clearTimeout) || clearTimeout)(handle); + }, + delegate: undefined +}; +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/reportUnhandledError.js + + +function reportUnhandledError(err) { + timeoutProvider.setTimeout(function () { + var onUnhandledError = config.onUnhandledError; + if (onUnhandledError) { + onUnhandledError(err); + } else { + throw err; + } + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/noop.js +function noop() {} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/NotificationFactories.js +var COMPLETE_NOTIFICATION = function () { + return createNotification('C', undefined, undefined); +}(); +function errorNotification(error) { + return createNotification('E', undefined, error); +} +function nextNotification(value) { + return createNotification('N', value, undefined); +} +function createNotification(kind, value, error) { + return { + kind: kind, + value: value, + error: error + }; +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/errorContext.js + +var context = null; +function errorContext(cb) { + if (config.useDeprecatedSynchronousErrorHandling) { + var isRoot = !context; + if (isRoot) { + context = { + errorThrown: false, + error: null + }; + } + cb(); + if (isRoot) { + var _a = context, + errorThrown = _a.errorThrown, + error = _a.error; + context = null; + if (errorThrown) { + throw error; + } + } + } else { + cb(); + } +} +function captureError(err) { + if (config.useDeprecatedSynchronousErrorHandling && context) { + context.errorThrown = true; + context.error = err; + } +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/Subscriber.js + + + + + + + + + +var Subscriber = function (_super) { + __extends(Subscriber, _super); + function Subscriber(destination) { + var _this = _super.call(this) || this; + _this.isStopped = false; + if (destination) { + _this.destination = destination; + if (isSubscription(destination)) { + destination.add(_this); + } + } else { + _this.destination = EMPTY_OBSERVER; + } + return _this; + } + Subscriber.create = function (next, error, complete) { + return new SafeSubscriber(next, error, complete); + }; + Subscriber.prototype.next = function (value) { + if (this.isStopped) { + handleStoppedNotification(nextNotification(value), this); + } else { + this._next(value); + } + }; + Subscriber.prototype.error = function (err) { + if (this.isStopped) { + handleStoppedNotification(errorNotification(err), this); + } else { + this.isStopped = true; + this._error(err); + } + }; + Subscriber.prototype.complete = function () { + if (this.isStopped) { + handleStoppedNotification(COMPLETE_NOTIFICATION, this); + } else { + this.isStopped = true; + this._complete(); + } + }; + Subscriber.prototype.unsubscribe = function () { + if (!this.closed) { + this.isStopped = true; + _super.prototype.unsubscribe.call(this); + this.destination = null; + } + }; + Subscriber.prototype._next = function (value) { + this.destination.next(value); + }; + Subscriber.prototype._error = function (err) { + try { + this.destination.error(err); + } finally { + this.unsubscribe(); + } + }; + Subscriber.prototype._complete = function () { + try { + this.destination.complete(); + } finally { + this.unsubscribe(); + } + }; + return Subscriber; +}(Subscription); + +var _bind = Function.prototype.bind; +function bind(fn, thisArg) { + return _bind.call(fn, thisArg); +} +var ConsumerObserver = function () { + function ConsumerObserver(partialObserver) { + this.partialObserver = partialObserver; + } + ConsumerObserver.prototype.next = function (value) { + var partialObserver = this.partialObserver; + if (partialObserver.next) { + try { + partialObserver.next(value); + } catch (error) { + handleUnhandledError(error); + } + } + }; + ConsumerObserver.prototype.error = function (err) { + var partialObserver = this.partialObserver; + if (partialObserver.error) { + try { + partialObserver.error(err); + } catch (error) { + handleUnhandledError(error); + } + } else { + handleUnhandledError(err); + } + }; + ConsumerObserver.prototype.complete = function () { + var partialObserver = this.partialObserver; + if (partialObserver.complete) { + try { + partialObserver.complete(); + } catch (error) { + handleUnhandledError(error); + } + } + }; + return ConsumerObserver; +}(); +var SafeSubscriber = function (_super) { + __extends(SafeSubscriber, _super); + function SafeSubscriber(observerOrNext, error, complete) { + var _this = _super.call(this) || this; + var partialObserver; + if (isFunction_isFunction(observerOrNext) || !observerOrNext) { + partialObserver = { + next: observerOrNext !== null && observerOrNext !== void 0 ? observerOrNext : undefined, + error: error !== null && error !== void 0 ? error : undefined, + complete: complete !== null && complete !== void 0 ? complete : undefined + }; + } else { + var context_1; + if (_this && config.useDeprecatedNextContext) { + context_1 = Object.create(observerOrNext); + context_1.unsubscribe = function () { + return _this.unsubscribe(); + }; + partialObserver = { + next: observerOrNext.next && bind(observerOrNext.next, context_1), + error: observerOrNext.error && bind(observerOrNext.error, context_1), + complete: observerOrNext.complete && bind(observerOrNext.complete, context_1) + }; + } else { + partialObserver = observerOrNext; + } + } + _this.destination = new ConsumerObserver(partialObserver); + return _this; + } + return SafeSubscriber; +}(Subscriber); + +function handleUnhandledError(error) { + if (config.useDeprecatedSynchronousErrorHandling) { + captureError(error); + } else { + reportUnhandledError(error); + } +} +function defaultErrorHandler(err) { + throw err; +} +function handleStoppedNotification(notification, subscriber) { + var onStoppedNotification = config.onStoppedNotification; + onStoppedNotification && timeoutProvider.setTimeout(function () { + return onStoppedNotification(notification, subscriber); + }); +} +var EMPTY_OBSERVER = { + closed: true, + next: noop, + error: defaultErrorHandler, + complete: noop +}; +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/symbol/observable.js +var observable = function () { + return typeof Symbol === 'function' && Symbol.observable || '@@observable'; +}(); +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/identity.js +function identity(x) { + return x; +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/pipe.js + +function pipe() { + var fns = []; + for (var _i = 0; _i < arguments.length; _i++) { + fns[_i] = arguments[_i]; + } + return pipeFromArray(fns); +} +function pipeFromArray(fns) { + if (fns.length === 0) { + return identity; + } + if (fns.length === 1) { + return fns[0]; + } + return function piped(input) { + return fns.reduce(function (prev, fn) { + return fn(prev); + }, input); + }; +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/Observable.js + + + + + + + +var Observable = function () { + function Observable(subscribe) { + if (subscribe) { + this._subscribe = subscribe; + } + } + Observable.prototype.lift = function (operator) { + var observable = new Observable(); + observable.source = this; + observable.operator = operator; + return observable; + }; + Observable.prototype.subscribe = function (observerOrNext, error, complete) { + var _this = this; + var subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete); + errorContext(function () { + var _a = _this, + operator = _a.operator, + source = _a.source; + subscriber.add(operator ? operator.call(subscriber, source) : source ? _this._subscribe(subscriber) : _this._trySubscribe(subscriber)); + }); + return subscriber; + }; + Observable.prototype._trySubscribe = function (sink) { + try { + return this._subscribe(sink); + } catch (err) { + sink.error(err); + } + }; + Observable.prototype.forEach = function (next, promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var subscriber = new SafeSubscriber({ + next: function (value) { + try { + next(value); + } catch (err) { + reject(err); + subscriber.unsubscribe(); + } + }, + error: reject, + complete: resolve + }); + _this.subscribe(subscriber); + }); + }; + Observable.prototype._subscribe = function (subscriber) { + var _a; + return (_a = this.source) === null || _a === void 0 ? void 0 : _a.subscribe(subscriber); + }; + Observable.prototype[observable] = function () { + return this; + }; + Observable.prototype.pipe = function () { + var operations = []; + for (var _i = 0; _i < arguments.length; _i++) { + operations[_i] = arguments[_i]; + } + return pipeFromArray(operations)(this); + }; + Observable.prototype.toPromise = function (promiseCtor) { + var _this = this; + promiseCtor = getPromiseCtor(promiseCtor); + return new promiseCtor(function (resolve, reject) { + var value; + _this.subscribe(function (x) { + return value = x; + }, function (err) { + return reject(err); + }, function () { + return resolve(value); + }); + }); + }; + Observable.create = function (subscribe) { + return new Observable(subscribe); + }; + return Observable; +}(); + +function getPromiseCtor(promiseCtor) { + var _a; + return (_a = promiseCtor !== null && promiseCtor !== void 0 ? promiseCtor : config.Promise) !== null && _a !== void 0 ? _a : Promise; +} +function isObserver(value) { + return value && isFunction_isFunction(value.next) && isFunction_isFunction(value.error) && isFunction_isFunction(value.complete); +} +function isSubscriber(value) { + return value && value instanceof Subscriber || isObserver(value) && isSubscription(value); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isInteropObservable.js + + +function isInteropObservable(input) { + return isFunction_isFunction(input[observable]); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isAsyncIterable.js + +function isAsyncIterable(obj) { + return Symbol.asyncIterator && isFunction_isFunction(obj === null || obj === void 0 ? void 0 : obj[Symbol.asyncIterator]); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/throwUnobservableError.js +function createInvalidObservableTypeError(input) { + return new TypeError("You provided " + (input !== null && typeof input === 'object' ? 'an invalid object' : "'" + input + "'") + " where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable."); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/symbol/iterator.js +function getSymbolIterator() { + if (typeof Symbol !== 'function' || !Symbol.iterator) { + return '@@iterator'; + } + return Symbol.iterator; +} +var iterator_iterator = getSymbolIterator(); +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isIterable.js + + +function isIterable(input) { + return isFunction_isFunction(input === null || input === void 0 ? void 0 : input[iterator_iterator]); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/isReadableStreamLike.js + + +function readableStreamLikeToAsyncGenerator(readableStream) { + return __asyncGenerator(this, arguments, function readableStreamLikeToAsyncGenerator_1() { + var reader, _a, value, done; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + reader = readableStream.getReader(); + _b.label = 1; + case 1: + _b.trys.push([1,, 9, 10]); + _b.label = 2; + case 2: + if (false) {} + return [4, __await(reader.read())]; + case 3: + _a = _b.sent(), value = _a.value, done = _a.done; + if (!done) return [3, 5]; + return [4, __await(void 0)]; + case 4: + return [2, _b.sent()]; + case 5: + return [4, __await(value)]; + case 6: + return [4, _b.sent()]; + case 7: + _b.sent(); + return [3, 2]; + case 8: + return [3, 10]; + case 9: + reader.releaseLock(); + return [7]; + case 10: + return [2]; + } + }); + }); +} +function isReadableStreamLike(obj) { + return isFunction_isFunction(obj === null || obj === void 0 ? void 0 : obj.getReader); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/observable/innerFrom.js + + + + + + + + + + + + +function innerFrom(input) { + if (input instanceof Observable) { + return input; + } + if (input != null) { + if (isInteropObservable(input)) { + return fromInteropObservable(input); + } + if (isArrayLike(input)) { + return fromArrayLike(input); + } + if (isPromise(input)) { + return fromPromise(input); + } + if (isAsyncIterable(input)) { + return fromAsyncIterable(input); + } + if (isIterable(input)) { + return fromIterable(input); + } + if (isReadableStreamLike(input)) { + return fromReadableStreamLike(input); + } + } + throw createInvalidObservableTypeError(input); +} +function fromInteropObservable(obj) { + return new Observable(function (subscriber) { + var obs = obj[observable](); + if (isFunction_isFunction(obs.subscribe)) { + return obs.subscribe(subscriber); + } + throw new TypeError('Provided object does not correctly implement Symbol.observable'); + }); +} +function fromArrayLike(array) { + return new Observable(function (subscriber) { + for (var i = 0; i < array.length && !subscriber.closed; i++) { + subscriber.next(array[i]); + } + subscriber.complete(); + }); +} +function fromPromise(promise) { + return new Observable(function (subscriber) { + promise.then(function (value) { + if (!subscriber.closed) { + subscriber.next(value); + subscriber.complete(); + } + }, function (err) { + return subscriber.error(err); + }).then(null, reportUnhandledError); + }); +} +function fromIterable(iterable) { + return new Observable(function (subscriber) { + var e_1, _a; + try { + for (var iterable_1 = __values(iterable), iterable_1_1 = iterable_1.next(); !iterable_1_1.done; iterable_1_1 = iterable_1.next()) { + var value = iterable_1_1.value; + subscriber.next(value); + if (subscriber.closed) { + return; + } + } + } catch (e_1_1) { + e_1 = { + error: e_1_1 + }; + } finally { + try { + if (iterable_1_1 && !iterable_1_1.done && (_a = iterable_1.return)) _a.call(iterable_1); + } finally { + if (e_1) throw e_1.error; + } + } + subscriber.complete(); + }); +} +function fromAsyncIterable(asyncIterable) { + return new Observable(function (subscriber) { + process(asyncIterable, subscriber).catch(function (err) { + return subscriber.error(err); + }); + }); +} +function fromReadableStreamLike(readableStream) { + return fromAsyncIterable(readableStreamLikeToAsyncGenerator(readableStream)); +} +function process(asyncIterable, subscriber) { + var asyncIterable_1, asyncIterable_1_1; + var e_2, _a; + return __awaiter(this, void 0, void 0, function () { + var value, e_2_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + _b.trys.push([0, 5, 6, 11]); + asyncIterable_1 = __asyncValues(asyncIterable); + _b.label = 1; + case 1: + return [4, asyncIterable_1.next()]; + case 2: + if (!(asyncIterable_1_1 = _b.sent(), !asyncIterable_1_1.done)) return [3, 4]; + value = asyncIterable_1_1.value; + subscriber.next(value); + if (subscriber.closed) { + return [2]; + } + _b.label = 3; + case 3: + return [3, 1]; + case 4: + return [3, 11]; + case 5: + e_2_1 = _b.sent(); + e_2 = { + error: e_2_1 + }; + return [3, 11]; + case 6: + _b.trys.push([6,, 9, 10]); + if (!(asyncIterable_1_1 && !asyncIterable_1_1.done && (_a = asyncIterable_1.return))) return [3, 8]; + return [4, _a.call(asyncIterable_1)]; + case 7: + _b.sent(); + _b.label = 8; + case 8: + return [3, 10]; + case 9: + if (e_2) throw e_2.error; + return [7]; + case 10: + return [7]; + case 11: + subscriber.complete(); + return [2]; + } + }); + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/executeSchedule.js +function executeSchedule(parentSubscription, scheduler, work, delay, repeat) { + if (delay === void 0) { + delay = 0; + } + if (repeat === void 0) { + repeat = false; + } + var scheduleSubscription = scheduler.schedule(function () { + work(); + if (repeat) { + parentSubscription.add(this.schedule(null, delay)); + } else { + this.unsubscribe(); + } + }, delay); + parentSubscription.add(scheduleSubscription); + if (!repeat) { + return scheduleSubscription; + } +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/util/lift.js + +function hasLift(source) { + return isFunction_isFunction(source === null || source === void 0 ? void 0 : source.lift); +} +function operate(init) { + return function (source) { + if (hasLift(source)) { + return source.lift(function (liftedSource) { + try { + return init(liftedSource, this); + } catch (err) { + this.error(err); + } + }); + } + throw new TypeError('Unable to lift unknown Observable type'); + }; +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/operators/OperatorSubscriber.js + + +function createOperatorSubscriber(destination, onNext, onComplete, onError, onFinalize) { + return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize); +} +var OperatorSubscriber = function (_super) { + __extends(OperatorSubscriber, _super); + function OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize, shouldUnsubscribe) { + var _this = _super.call(this, destination) || this; + _this.onFinalize = onFinalize; + _this.shouldUnsubscribe = shouldUnsubscribe; + _this._next = onNext ? function (value) { + try { + onNext(value); + } catch (err) { + destination.error(err); + } + } : _super.prototype._next; + _this._error = onError ? function (err) { + try { + onError(err); + } catch (err) { + destination.error(err); + } finally { + this.unsubscribe(); + } + } : _super.prototype._error; + _this._complete = onComplete ? function () { + try { + onComplete(); + } catch (err) { + destination.error(err); + } finally { + this.unsubscribe(); + } + } : _super.prototype._complete; + return _this; + } + OperatorSubscriber.prototype.unsubscribe = function () { + var _a; + if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) { + var closed_1 = this.closed; + _super.prototype.unsubscribe.call(this); + !closed_1 && ((_a = this.onFinalize) === null || _a === void 0 ? void 0 : _a.call(this)); + } + }; + return OperatorSubscriber; +}(Subscriber); + +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/operators/observeOn.js + + + +function observeOn(scheduler, delay) { + if (delay === void 0) { + delay = 0; + } + return operate(function (source, subscriber) { + source.subscribe(createOperatorSubscriber(subscriber, function (value) { + return executeSchedule(subscriber, scheduler, function () { + return subscriber.next(value); + }, delay); + }, function () { + return executeSchedule(subscriber, scheduler, function () { + return subscriber.complete(); + }, delay); + }, function (err) { + return executeSchedule(subscriber, scheduler, function () { + return subscriber.error(err); + }, delay); + })); + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/operators/subscribeOn.js + +function subscribeOn(scheduler, delay) { + if (delay === void 0) { + delay = 0; + } + return operate(function (source, subscriber) { + subscriber.add(scheduler.schedule(function () { + return source.subscribe(subscriber); + }, delay)); + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/scheduleObservable.js + + + +function scheduleObservable(input, scheduler) { + return innerFrom(input).pipe(subscribeOn(scheduler), observeOn(scheduler)); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/schedulePromise.js + + + +function schedulePromise(input, scheduler) { + return innerFrom(input).pipe(subscribeOn(scheduler), observeOn(scheduler)); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/scheduleArray.js + +function scheduleArray(input, scheduler) { + return new Observable(function (subscriber) { + var i = 0; + return scheduler.schedule(function () { + if (i === input.length) { + subscriber.complete(); + } else { + subscriber.next(input[i++]); + if (!subscriber.closed) { + this.schedule(); + } + } + }); + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/scheduleIterable.js + + + + +function scheduleIterable(input, scheduler) { + return new Observable(function (subscriber) { + var iterator; + executeSchedule(subscriber, scheduler, function () { + iterator = input[iterator_iterator](); + executeSchedule(subscriber, scheduler, function () { + var _a; + var value; + var done; + try { + _a = iterator.next(), value = _a.value, done = _a.done; + } catch (err) { + subscriber.error(err); + return; + } + if (done) { + subscriber.complete(); + } else { + subscriber.next(value); + } + }, 0, true); + }); + return function () { + return isFunction_isFunction(iterator === null || iterator === void 0 ? void 0 : iterator.return) && iterator.return(); + }; + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/scheduleAsyncIterable.js + + +function scheduleAsyncIterable(input, scheduler) { + if (!input) { + throw new Error('Iterable cannot be null'); + } + return new Observable(function (subscriber) { + executeSchedule(subscriber, scheduler, function () { + var iterator = input[Symbol.asyncIterator](); + executeSchedule(subscriber, scheduler, function () { + iterator.next().then(function (result) { + if (result.done) { + subscriber.complete(); + } else { + subscriber.next(result.value); + } + }); + }, 0, true); + }); + }); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/scheduleReadableStreamLike.js + + +function scheduleReadableStreamLike(input, scheduler) { + return scheduleAsyncIterable(readableStreamLikeToAsyncGenerator(input), scheduler); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/scheduled/scheduled.js + + + + + + + + + + + + + +function scheduled(input, scheduler) { + if (input != null) { + if (isInteropObservable(input)) { + return scheduleObservable(input, scheduler); + } + if (isArrayLike(input)) { + return scheduleArray(input, scheduler); + } + if (isPromise(input)) { + return schedulePromise(input, scheduler); + } + if (isAsyncIterable(input)) { + return scheduleAsyncIterable(input, scheduler); + } + if (isIterable(input)) { + return scheduleIterable(input, scheduler); + } + if (isReadableStreamLike(input)) { + return scheduleReadableStreamLike(input, scheduler); + } + } + throw createInvalidObservableTypeError(input); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/observable/from.js + + +function from(input, scheduler) { + return scheduler ? scheduled(input, scheduler) : innerFrom(input); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/observable/of.js + + +function of() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var scheduler = popScheduler(args); + return from(args, scheduler); +} +;// CONCATENATED MODULE: ../../node_modules/rxjs/dist/esm5/internal/operators/switchMap.js + + + +function switchMap(project, resultSelector) { + return operate(function (source, subscriber) { + var innerSubscriber = null; + var index = 0; + var isComplete = false; + var checkComplete = function () { + return isComplete && !innerSubscriber && subscriber.complete(); + }; + source.subscribe(createOperatorSubscriber(subscriber, function (value) { + innerSubscriber === null || innerSubscriber === void 0 ? void 0 : innerSubscriber.unsubscribe(); + var innerIndex = 0; + var outerIndex = index++; + innerFrom(project(value, outerIndex)).subscribe(innerSubscriber = createOperatorSubscriber(subscriber, function (innerValue) { + return subscriber.next(resultSelector ? resultSelector(value, innerValue, outerIndex, innerIndex++) : innerValue); + }, function () { + innerSubscriber = null; + checkComplete(); + })); + }, function () { + isComplete = true; + checkComplete(); + })); + }); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/domain.js +/** + * Check if `vhost` is a valid suffix of `hostname` (top-domain) + * + * It means that `vhost` needs to be a suffix of `hostname` and we then need to + * make sure that: either they are equal, or the character preceding `vhost` in + * `hostname` is a '.' (it should not be a partial label). + * + * * hostname = 'not.evil.com' and vhost = 'vil.com' => not ok + * * hostname = 'not.evil.com' and vhost = 'evil.com' => ok + * * hostname = 'not.evil.com' and vhost = 'not.evil.com' => ok + */ +function shareSameDomainSuffix(hostname, vhost) { + if (hostname.endsWith(vhost)) { + return hostname.length === vhost.length || hostname[hostname.length - vhost.length - 1] === '.'; + } + return false; +} +/** + * Given a hostname and its public suffix, extract the general domain. + */ +function extractDomainWithSuffix(hostname, publicSuffix) { + // Locate the index of the last '.' in the part of the `hostname` preceding + // the public suffix. + // + // examples: + // 1. not.evil.co.uk => evil.co.uk + // ^ ^ + // | | start of public suffix + // | index of the last dot + // + // 2. example.co.uk => example.co.uk + // ^ ^ + // | | start of public suffix + // | + // | (-1) no dot found before the public suffix + const publicSuffixIndex = hostname.length - publicSuffix.length - 2; + const lastDotBeforeSuffixIndex = hostname.lastIndexOf('.', publicSuffixIndex); + // No '.' found, then `hostname` is the general domain (no sub-domain) + if (lastDotBeforeSuffixIndex === -1) { + return hostname; + } + // Extract the part between the last '.' + return hostname.slice(lastDotBeforeSuffixIndex + 1); +} +/** + * Detects the domain based on rules and upon and a host string + */ +function getDomain(suffix, hostname, options) { + // Check if `hostname` ends with a member of `validHosts`. + if (options.validHosts !== null) { + const validHosts = options.validHosts; + for (const vhost of validHosts) { + if ( /*@__INLINE__*/shareSameDomainSuffix(hostname, vhost)) { + return vhost; + } + } + } + let numberOfLeadingDots = 0; + if (hostname.startsWith('.')) { + while (numberOfLeadingDots < hostname.length && hostname[numberOfLeadingDots] === '.') { + numberOfLeadingDots += 1; + } + } + // If `hostname` is a valid public suffix, then there is no domain to return. + // Since we already know that `getPublicSuffix` returns a suffix of `hostname` + // there is no need to perform a string comparison and we only compare the + // size. + if (suffix.length === hostname.length - numberOfLeadingDots) { + return null; + } + // To extract the general domain, we start by identifying the public suffix + // (if any), then consider the domain to be the public suffix with one added + // level of depth. (e.g.: if hostname is `not.evil.co.uk` and public suffix: + // `co.uk`, then we take one more level: `evil`, giving the final result: + // `evil.co.uk`). + return /*@__INLINE__*/extractDomainWithSuffix(hostname, suffix); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/domain-without-suffix.js +/** + * Return the part of domain without suffix. + * + * Example: for domain 'foo.com', the result would be 'foo'. + */ +function getDomainWithoutSuffix(domain, suffix) { + // Note: here `domain` and `suffix` cannot have the same length because in + // this case we set `domain` to `null` instead. It is thus safe to assume + // that `suffix` is shorter than `domain`. + return domain.slice(0, -suffix.length - 1); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/extract-hostname.js +/** + * @param url - URL we want to extract a hostname from. + * @param urlIsValidHostname - hint from caller; true if `url` is already a valid hostname. + */ +function extractHostname(url, urlIsValidHostname) { + let start = 0; + let end = url.length; + let hasUpper = false; + // If url is not already a valid hostname, then try to extract hostname. + if (!urlIsValidHostname) { + // Special handling of data URLs + if (url.startsWith('data:')) { + return null; + } + // Trim leading spaces + while (start < url.length && url.charCodeAt(start) <= 32) { + start += 1; + } + // Trim trailing spaces + while (end > start + 1 && url.charCodeAt(end - 1) <= 32) { + end -= 1; + } + // Skip scheme. + if (url.charCodeAt(start) === 47 /* '/' */ && url.charCodeAt(start + 1) === 47 /* '/' */) { + start += 2; + } else { + const indexOfProtocol = url.indexOf(':/', start); + if (indexOfProtocol !== -1) { + // Implement fast-path for common protocols. We expect most protocols + // should be one of these 4 and thus we will not need to perform the + // more expansive validity check most of the time. + const protocolSize = indexOfProtocol - start; + const c0 = url.charCodeAt(start); + const c1 = url.charCodeAt(start + 1); + const c2 = url.charCodeAt(start + 2); + const c3 = url.charCodeAt(start + 3); + const c4 = url.charCodeAt(start + 4); + if (protocolSize === 5 && c0 === 104 /* 'h' */ && c1 === 116 /* 't' */ && c2 === 116 /* 't' */ && c3 === 112 /* 'p' */ && c4 === 115 /* 's' */) { + // https + } else if (protocolSize === 4 && c0 === 104 /* 'h' */ && c1 === 116 /* 't' */ && c2 === 116 /* 't' */ && c3 === 112 /* 'p' */) { + // http + } else if (protocolSize === 3 && c0 === 119 /* 'w' */ && c1 === 115 /* 's' */ && c2 === 115 /* 's' */) { + // wss + } else if (protocolSize === 2 && c0 === 119 /* 'w' */ && c1 === 115 /* 's' */) { + // ws + } else { + // Check that scheme is valid + for (let i = start; i < indexOfProtocol; i += 1) { + const lowerCaseCode = url.charCodeAt(i) | 32; + if (!(lowerCaseCode >= 97 && lowerCaseCode <= 122 || + // [a, z] + lowerCaseCode >= 48 && lowerCaseCode <= 57 || + // [0, 9] + lowerCaseCode === 46 || + // '.' + lowerCaseCode === 45 || + // '-' + lowerCaseCode === 43 // '+' + )) { + return null; + } + } + } + // Skip 0, 1 or more '/' after ':/' + start = indexOfProtocol + 2; + while (url.charCodeAt(start) === 47 /* '/' */) { + start += 1; + } + } + } + // Detect first occurrence of '/', '?' or '#'. We also keep track of the + // last occurrence of '@', ']' or ':' to speed-up subsequent parsing of + // (respectively), identifier, ipv6 or port. + let indexOfIdentifier = -1; + let indexOfClosingBracket = -1; + let indexOfPort = -1; + for (let i = start; i < end; i += 1) { + const code = url.charCodeAt(i); + if (code === 35 || + // '#' + code === 47 || + // '/' + code === 63 // '?' + ) { + end = i; + break; + } else if (code === 64) { + // '@' + indexOfIdentifier = i; + } else if (code === 93) { + // ']' + indexOfClosingBracket = i; + } else if (code === 58) { + // ':' + indexOfPort = i; + } else if (code >= 65 && code <= 90) { + hasUpper = true; + } + } + // Detect identifier: '@' + if (indexOfIdentifier !== -1 && indexOfIdentifier > start && indexOfIdentifier < end) { + start = indexOfIdentifier + 1; + } + // Handle ipv6 addresses + if (url.charCodeAt(start) === 91 /* '[' */) { + if (indexOfClosingBracket !== -1) { + return url.slice(start + 1, indexOfClosingBracket).toLowerCase(); + } + return null; + } else if (indexOfPort !== -1 && indexOfPort > start && indexOfPort < end) { + // Detect port: ':' + end = indexOfPort; + } + } + // Trim trailing dots + while (end > start + 1 && url.charCodeAt(end - 1) === 46 /* '.' */) { + end -= 1; + } + const hostname = start !== 0 || end !== url.length ? url.slice(start, end) : url; + if (hasUpper) { + return hostname.toLowerCase(); + } + return hostname; +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/is-ip.js +/** + * Check if a hostname is an IP. You should be aware that this only works + * because `hostname` is already garanteed to be a valid hostname! + */ +function isProbablyIpv4(hostname) { + // Cannot be shorted than 1.1.1.1 + if (hostname.length < 7) { + return false; + } + // Cannot be longer than: 255.255.255.255 + if (hostname.length > 15) { + return false; + } + let numberOfDots = 0; + for (let i = 0; i < hostname.length; i += 1) { + const code = hostname.charCodeAt(i); + if (code === 46 /* '.' */) { + numberOfDots += 1; + } else if (code < 48 /* '0' */ || code > 57 /* '9' */) { + return false; + } + } + return numberOfDots === 3 && hostname.charCodeAt(0) !== 46 /* '.' */ && hostname.charCodeAt(hostname.length - 1) !== 46 /* '.' */; +} +/** + * Similar to isProbablyIpv4. + */ +function isProbablyIpv6(hostname) { + if (hostname.length < 3) { + return false; + } + let start = hostname.startsWith('[') ? 1 : 0; + let end = hostname.length; + if (hostname[end - 1] === ']') { + end -= 1; + } + // We only consider the maximum size of a normal IPV6. Note that this will + // fail on so-called "IPv4 mapped IPv6 addresses" but this is a corner-case + // and a proper validation library should be used for these. + if (end - start > 39) { + return false; + } + let hasColon = false; + for (; start < end; start += 1) { + const code = hostname.charCodeAt(start); + if (code === 58 /* ':' */) { + hasColon = true; + } else if (!(code >= 48 && code <= 57 || + // 0-9 + code >= 97 && code <= 102 || + // a-f + code >= 65 && code <= 90 // A-F + )) { + return false; + } + } + return hasColon; +} +/** + * Check if `hostname` is *probably* a valid ip addr (either ipv6 or ipv4). + * This *will not* work on any string. We need `hostname` to be a valid + * hostname. + */ +function isIp(hostname) { + return isProbablyIpv6(hostname) || isProbablyIpv4(hostname); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/is-valid.js +/** + * Implements fast shallow verification of hostnames. This does not perform a + * struct check on the content of labels (classes of Unicode characters, etc.) + * but instead check that the structure is valid (number of labels, length of + * labels, etc.). + * + * If you need stricter validation, consider using an external library. + */ +function isValidAscii(code) { + return code >= 97 && code <= 122 || code >= 48 && code <= 57 || code > 127; +} +/** + * Check if a hostname string is valid. It's usually a preliminary check before + * trying to use getDomain or anything else. + * + * Beware: it does not check if the TLD exists. + */ +/* harmony default export */ function is_valid(hostname) { + if (hostname.length > 255) { + return false; + } + if (hostname.length === 0) { + return false; + } + if ( /*@__INLINE__*/!isValidAscii(hostname.charCodeAt(0)) && hostname.charCodeAt(0) !== 46 && + // '.' (dot) + hostname.charCodeAt(0) !== 95 // '_' (underscore) + ) { + return false; + } + // Validate hostname according to RFC + let lastDotIndex = -1; + let lastCharCode = -1; + const len = hostname.length; + for (let i = 0; i < len; i += 1) { + const code = hostname.charCodeAt(i); + if (code === 46 /* '.' */) { + if ( + // Check that previous label is < 63 bytes long (64 = 63 + '.') + i - lastDotIndex > 64 || + // Check that previous character was not already a '.' + lastCharCode === 46 || + // Check that the previous label does not end with a '-' (dash) + lastCharCode === 45 || + // Check that the previous label does not end with a '_' (underscore) + lastCharCode === 95) { + return false; + } + lastDotIndex = i; + } else if (!( /*@__INLINE__*/isValidAscii(code) || code === 45 || code === 95)) { + // Check if there is a forbidden character in the label + return false; + } + lastCharCode = code; + } + return ( + // Check that last label is shorter than 63 chars + len - lastDotIndex - 1 <= 63 && + // Check that the last character is an allowed trailing label character. + // Since we already checked that the char is a valid hostname character, + // we only need to check that it's different from '-'. + lastCharCode !== 45 + ); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/options.js +function setDefaultsImpl({ + allowIcannDomains = true, + allowPrivateDomains = false, + detectIp = true, + extractHostname = true, + mixedInputs = true, + validHosts = null, + validateHostname = true +}) { + return { + allowIcannDomains, + allowPrivateDomains, + detectIp, + extractHostname, + mixedInputs, + validHosts, + validateHostname + }; +} +const DEFAULT_OPTIONS = /*@__INLINE__*/setDefaultsImpl({}); +function setDefaults(options) { + if (options === undefined) { + return DEFAULT_OPTIONS; + } + return /*@__INLINE__*/setDefaultsImpl(options); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/subdomain.js +/** + * Returns the subdomain of a hostname string + */ +function getSubdomain(hostname, domain) { + // If `hostname` and `domain` are the same, then there is no sub-domain + if (domain.length === hostname.length) { + return ''; + } + return hostname.slice(0, -domain.length - 1); +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/factory.js +/** + * Implement a factory allowing to plug different implementations of suffix + * lookup (e.g.: using a trie or the packed hashes datastructures). This is used + * and exposed in `tldts.ts` and `tldts-experimental.ts` bundle entrypoints. + */ + + + + + + + +function getEmptyResult() { + return { + domain: null, + domainWithoutSuffix: null, + hostname: null, + isIcann: null, + isIp: null, + isPrivate: null, + publicSuffix: null, + subdomain: null + }; +} +function factory_resetResult(result) { + result.domain = null; + result.domainWithoutSuffix = null; + result.hostname = null; + result.isIcann = null; + result.isIp = null; + result.isPrivate = null; + result.publicSuffix = null; + result.subdomain = null; +} +function factory_parseImpl(url, step, suffixLookup, partialOptions, result) { + const options = /*@__INLINE__*/setDefaults(partialOptions); + // Very fast approximate check to make sure `url` is a string. This is needed + // because the library will not necessarily be used in a typed setup and + // values of arbitrary types might be given as argument. + if (typeof url !== 'string') { + return result; + } + // Extract hostname from `url` only if needed. This can be made optional + // using `options.extractHostname`. This option will typically be used + // whenever we are sure the inputs to `parse` are already hostnames and not + // arbitrary URLs. + // + // `mixedInput` allows to specify if we expect a mix of URLs and hostnames + // as input. If only hostnames are expected then `extractHostname` can be + // set to `false` to speed-up parsing. If only URLs are expected then + // `mixedInputs` can be set to `false`. The `mixedInputs` is only a hint + // and will not change the behavior of the library. + if (!options.extractHostname) { + result.hostname = url; + } else if (options.mixedInputs) { + result.hostname = extractHostname(url, is_valid(url)); + } else { + result.hostname = extractHostname(url, false); + } + if (step === 0 /* FLAG.HOSTNAME */ || result.hostname === null) { + return result; + } + // Check if `hostname` is a valid ip address + if (options.detectIp) { + result.isIp = isIp(result.hostname); + if (result.isIp) { + return result; + } + } + // Perform optional hostname validation. If hostname is not valid, no need to + // go further as there will be no valid domain or sub-domain. + if (options.validateHostname && options.extractHostname && !is_valid(result.hostname)) { + result.hostname = null; + return result; + } + // Extract public suffix + suffixLookup(result.hostname, options, result); + if (step === 2 /* FLAG.PUBLIC_SUFFIX */ || result.publicSuffix === null) { + return result; + } + // Extract domain + result.domain = getDomain(result.publicSuffix, result.hostname, options); + if (step === 3 /* FLAG.DOMAIN */ || result.domain === null) { + return result; + } + // Extract subdomain + result.subdomain = getSubdomain(result.hostname, result.domain); + if (step === 4 /* FLAG.SUB_DOMAIN */) { + return result; + } + // Extract domain without suffix + result.domainWithoutSuffix = getDomainWithoutSuffix(result.domain, result.publicSuffix); + return result; +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/src/lookup/fast-path.js +/* harmony default export */ function fast_path(hostname, options, out) { + // Fast path for very popular suffixes; this allows to by-pass lookup + // completely as well as any extra allocation or string manipulation. + if (!options.allowPrivateDomains && hostname.length > 3) { + const last = hostname.length - 1; + const c3 = hostname.charCodeAt(last); + const c2 = hostname.charCodeAt(last - 1); + const c1 = hostname.charCodeAt(last - 2); + const c0 = hostname.charCodeAt(last - 3); + if (c3 === 109 /* 'm' */ && c2 === 111 /* 'o' */ && c1 === 99 /* 'c' */ && c0 === 46 /* '.' */) { + out.isIcann = true; + out.isPrivate = false; + out.publicSuffix = 'com'; + return true; + } else if (c3 === 103 /* 'g' */ && c2 === 114 /* 'r' */ && c1 === 111 /* 'o' */ && c0 === 46 /* '.' */) { + out.isIcann = true; + out.isPrivate = false; + out.publicSuffix = 'org'; + return true; + } else if (c3 === 117 /* 'u' */ && c2 === 100 /* 'd' */ && c1 === 101 /* 'e' */ && c0 === 46 /* '.' */) { + out.isIcann = true; + out.isPrivate = false; + out.publicSuffix = 'edu'; + return true; + } else if (c3 === 118 /* 'v' */ && c2 === 111 /* 'o' */ && c1 === 103 /* 'g' */ && c0 === 46 /* '.' */) { + out.isIcann = true; + out.isPrivate = false; + out.publicSuffix = 'gov'; + return true; + } else if (c3 === 116 /* 't' */ && c2 === 101 /* 'e' */ && c1 === 110 /* 'n' */ && c0 === 46 /* '.' */) { + out.isIcann = true; + out.isPrivate = false; + out.publicSuffix = 'net'; + return true; + } else if (c3 === 101 /* 'e' */ && c2 === 100 /* 'd' */ && c1 === 46 /* '.' */) { + out.isIcann = true; + out.isPrivate = false; + out.publicSuffix = 'de'; + return true; + } + } + return false; +} +;// CONCATENATED MODULE: ../../node_modules/tldts-core/dist/es6/index.js + + + +;// CONCATENATED MODULE: ../../node_modules/tldts/dist/es6/src/data/trie.js +const exceptions = function () { + const _0 = [1, {}], + _1 = [0, { + "city": _0 + }]; + const exceptions = [0, { + "ck": [0, { + "www": _0 + }], + "jp": [0, { + "kawasaki": _1, + "kitakyushu": _1, + "kobe": _1, + "nagoya": _1, + "sapporo": _1, + "sendai": _1, + "yokohama": _1 + }] + }]; + return exceptions; +}(); +const rules = function () { + const _2 = [1, {}], + _3 = [2, {}], + _4 = [1, { + "gov": _2, + "com": _2, + "org": _2, + "net": _2, + "edu": _2 + }], + _5 = [0, { + "*": _3 + }], + _6 = [2, { + "id": _3 + }], + _7 = [1, { + "blogspot": _3 + }], + _8 = [1, { + "gov": _2 + }], + _9 = [0, { + "notebook": _3, + "studio": _3 + }], + _10 = [0, { + "notebook": _3 + }], + _11 = [0, { + "notebook": _3, + "notebook-fips": _3, + "studio": _3 + }], + _12 = [0, { + "notebook": _3, + "notebook-fips": _3, + "studio": _3, + "studio-fips": _3 + }], + _13 = [0, { + "*": _2 + }], + _14 = [0, { + "cloud": _3 + }], + _15 = [1, { + "co": _3 + }], + _16 = [2, { + "nodes": _3 + }], + _17 = [0, { + "my": _5 + }], + _18 = [0, { + "s3": _3, + "s3-accesspoint": _3, + "s3-website": _3 + }], + _19 = [0, { + "s3": _3, + "s3-accesspoint": _3 + }], + _20 = [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _19, + "s3": _3, + "s3-accesspoint": _3, + "s3-object-lambda": _3, + "s3-website": _3 + }], + _21 = [0, { + "direct": _3 + }], + _22 = [0, { + "webview-assets": _3 + }], + _23 = [0, { + "vfs": _3, + "webview-assets": _3 + }], + _24 = [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _18, + "s3": _3, + "s3-accesspoint": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + _25 = [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _19, + "s3": _3, + "s3-accesspoint": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + _26 = [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _18, + "s3": _3, + "s3-accesspoint": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "analytics-gateway": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + _27 = [0, { + "execute-api": _3, + "dualstack": _19, + "s3": _3, + "s3-accesspoint": _3, + "s3-object-lambda": _3, + "s3-website": _3 + }], + _28 = [0, { + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-fips": _3, + "s3-website": _3 + }], + _29 = [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _28, + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-fips": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + _30 = [0, { + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-fips": _3 + }], + _31 = [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _30, + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-fips": _3, + "s3-object-lambda": _3, + "s3-website": _3 + }], + _32 = [0, { + "auth": _3 + }], + _33 = [0, { + "auth": _3, + "auth-fips": _3 + }], + _34 = [0, { + "apps": _3 + }], + _35 = [0, { + "paas": _3 + }], + _36 = [0, { + "app": _3 + }], + _37 = [2, { + "eu": _3 + }], + _38 = [0, { + "site": _3 + }], + _39 = [0, { + "pages": _3 + }], + _40 = [1, { + "com": _2, + "edu": _2, + "net": _2, + "org": _2 + }], + _41 = [0, { + "j": _3 + }], + _42 = [0, { + "jelastic": _3 + }], + _43 = [0, { + "user": _3 + }], + _44 = [1, { + "ybo": _3 + }], + _45 = [0, { + "cust": _3, + "reservd": _3 + }], + _46 = [0, { + "cust": _3 + }], + _47 = [1, { + "gov": _2, + "edu": _2, + "mil": _2, + "com": _2, + "org": _2, + "net": _2 + }], + _48 = [0, { + "s3": _3 + }], + _49 = [1, { + "edu": _2, + "biz": _2, + "net": _2, + "org": _2, + "gov": _2, + "info": _2, + "com": _2 + }], + _50 = [1, { + "gov": _2, + "blogspot": _3 + }], + _51 = [1, { + "framer": _3 + }], + _52 = [1, { + "barsy": _3 + }], + _53 = [0, { + "forgot": _3 + }], + _54 = [1, { + "gs": _2 + }], + _55 = [0, { + "nes": _2 + }], + _56 = [1, { + "k12": _2, + "cc": _2, + "lib": _2 + }], + _57 = [1, { + "cc": _2, + "lib": _2 + }]; + const rules = [0, { + "ac": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "net": _2, + "mil": _2, + "org": _2, + "drr": _3, + "feedback": _3, + "forms": _3 + }], + "ad": [1, { + "nom": _2 + }], + "ae": [1, { + "co": _2, + "net": _2, + "org": _2, + "sch": _2, + "ac": _2, + "gov": _2, + "mil": _2, + "blogspot": _3 + }], + "aero": [1, { + "accident-investigation": _2, + "accident-prevention": _2, + "aerobatic": _2, + "aeroclub": _2, + "aerodrome": _2, + "agents": _2, + "aircraft": _2, + "airline": _2, + "airport": _2, + "air-surveillance": _2, + "airtraffic": _2, + "air-traffic-control": _2, + "ambulance": _2, + "amusement": _2, + "association": _2, + "author": _2, + "ballooning": _2, + "broker": _2, + "caa": _2, + "cargo": _2, + "catering": _2, + "certification": _2, + "championship": _2, + "charter": _2, + "civilaviation": _2, + "club": _2, + "conference": _2, + "consultant": _2, + "consulting": _2, + "control": _2, + "council": _2, + "crew": _2, + "design": _2, + "dgca": _2, + "educator": _2, + "emergency": _2, + "engine": _2, + "engineer": _2, + "entertainment": _2, + "equipment": _2, + "exchange": _2, + "express": _2, + "federation": _2, + "flight": _2, + "fuel": _2, + "gliding": _2, + "government": _2, + "groundhandling": _2, + "group": _2, + "hanggliding": _2, + "homebuilt": _2, + "insurance": _2, + "journal": _2, + "journalist": _2, + "leasing": _2, + "logistics": _2, + "magazine": _2, + "maintenance": _2, + "media": _2, + "microlight": _2, + "modelling": _2, + "navigation": _2, + "parachuting": _2, + "paragliding": _2, + "passenger-association": _2, + "pilot": _2, + "press": _2, + "production": _2, + "recreation": _2, + "repbody": _2, + "res": _2, + "research": _2, + "rotorcraft": _2, + "safety": _2, + "scientist": _2, + "services": _2, + "show": _2, + "skydiving": _2, + "software": _2, + "student": _2, + "trader": _2, + "trading": _2, + "trainer": _2, + "union": _2, + "workinggroup": _2, + "works": _2 + }], + "af": _4, + "ag": [1, { + "com": _2, + "org": _2, + "net": _2, + "co": _2, + "nom": _2 + }], + "ai": [1, { + "off": _2, + "com": _2, + "net": _2, + "org": _2, + "uwu": _3 + }], + "al": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "net": _2, + "org": _2, + "blogspot": _3 + }], + "am": [1, { + "co": _2, + "com": _2, + "commune": _2, + "net": _2, + "org": _2, + "radio": _3, + "blogspot": _3, + "neko": _3, + "nyaa": _3 + }], + "ao": [1, { + "ed": _2, + "gv": _2, + "og": _2, + "co": _2, + "pb": _2, + "it": _2 + }], + "aq": _2, + "ar": [1, { + "bet": _2, + "com": _7, + "coop": _2, + "edu": _2, + "gob": _2, + "gov": _2, + "int": _2, + "mil": _2, + "musica": _2, + "mutual": _2, + "net": _2, + "org": _2, + "senasa": _2, + "tur": _2 + }], + "arpa": [1, { + "e164": _2, + "in-addr": _2, + "ip6": _2, + "iris": _2, + "uri": _2, + "urn": _2 + }], + "as": _8, + "asia": [1, { + "cloudns": _3 + }], + "at": [1, { + "ac": [1, { + "sth": _2 + }], + "co": _7, + "gv": _2, + "or": _2, + "funkfeuer": [0, { + "wien": _3 + }], + "futurecms": [0, { + "*": _3, + "ex": _5, + "in": _5 + }], + "futurehosting": _3, + "futuremailing": _3, + "ortsinfo": [0, { + "ex": _5, + "kunden": _5 + }], + "biz": _3, + "info": _3, + "123webseite": _3, + "priv": _3, + "myspreadshop": _3, + "12hp": _3, + "2ix": _3, + "4lima": _3, + "lima-city": _3 + }], + "au": [1, { + "com": [1, { + "blogspot": _3, + "cloudlets": [0, { + "mel": _3 + }], + "myspreadshop": _3 + }], + "net": _2, + "org": _2, + "edu": [1, { + "act": _2, + "catholic": _2, + "nsw": [1, { + "schools": _2 + }], + "nt": _2, + "qld": _2, + "sa": _2, + "tas": _2, + "vic": _2, + "wa": _2 + }], + "gov": [1, { + "qld": _2, + "sa": _2, + "tas": _2, + "vic": _2, + "wa": _2 + }], + "asn": _2, + "id": _2, + "info": _2, + "conf": _2, + "oz": _2, + "act": _2, + "nsw": _2, + "nt": _2, + "qld": _2, + "sa": _2, + "tas": _2, + "vic": _2, + "wa": _2 + }], + "aw": [1, { + "com": _2 + }], + "ax": [1, { + "be": _3, + "cat": _3, + "es": _3, + "eu": _3, + "gg": _3, + "mc": _3, + "us": _3, + "xy": _3 + }], + "az": [1, { + "com": _2, + "net": _2, + "int": _2, + "gov": _2, + "org": _2, + "edu": _2, + "info": _2, + "pp": _2, + "mil": _2, + "name": _2, + "pro": _2, + "biz": _2 + }], + "ba": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "net": _2, + "org": _2, + "rs": _3, + "blogspot": _3 + }], + "bb": [1, { + "biz": _2, + "co": _2, + "com": _2, + "edu": _2, + "gov": _2, + "info": _2, + "net": _2, + "org": _2, + "store": _2, + "tv": _2 + }], + "bd": _13, + "be": [1, { + "ac": _2, + "webhosting": _3, + "blogspot": _3, + "interhostsolutions": _14, + "kuleuven": [0, { + "ezproxy": _3 + }], + "123website": _3, + "myspreadshop": _3, + "transurl": _5 + }], + "bf": _8, + "bg": [1, { + "0": _2, + "1": _2, + "2": _2, + "3": _2, + "4": _2, + "5": _2, + "6": _2, + "7": _2, + "8": _2, + "9": _2, + "a": _2, + "b": _2, + "c": _2, + "d": _2, + "e": _2, + "f": _2, + "g": _2, + "h": _2, + "i": _2, + "j": _2, + "k": _2, + "l": _2, + "m": _2, + "n": _2, + "o": _2, + "p": _2, + "q": _2, + "r": _2, + "s": _2, + "t": _2, + "u": _2, + "v": _2, + "w": _2, + "x": _2, + "y": _2, + "z": _2, + "blogspot": _3, + "barsy": _3 + }], + "bh": _4, + "bi": [1, { + "co": _2, + "com": _2, + "edu": _2, + "or": _2, + "org": _2 + }], + "biz": [1, { + "activetrail": _3, + "cloudns": _3, + "jozi": _3, + "dyndns": _3, + "for-better": _3, + "for-more": _3, + "for-some": _3, + "for-the": _3, + "selfip": _3, + "webhop": _3, + "orx": _3, + "mmafan": _3, + "myftp": _3, + "no-ip": _3, + "dscloud": _3 + }], + "bj": [1, { + "africa": _2, + "agro": _2, + "architectes": _2, + "assur": _2, + "avocats": _2, + "co": _2, + "com": _2, + "eco": _2, + "econo": _2, + "edu": _2, + "info": _2, + "loisirs": _2, + "money": _2, + "net": _2, + "org": _2, + "ote": _2, + "resto": _2, + "restaurant": _2, + "tourism": _2, + "univ": _2, + "blogspot": _3 + }], + "bm": _4, + "bn": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "net": _2, + "org": _2, + "co": _3 + }], + "bo": [1, { + "com": _2, + "edu": _2, + "gob": _2, + "int": _2, + "org": _2, + "net": _2, + "mil": _2, + "tv": _2, + "web": _2, + "academia": _2, + "agro": _2, + "arte": _2, + "blog": _2, + "bolivia": _2, + "ciencia": _2, + "cooperativa": _2, + "democracia": _2, + "deporte": _2, + "ecologia": _2, + "economia": _2, + "empresa": _2, + "indigena": _2, + "industria": _2, + "info": _2, + "medicina": _2, + "movimiento": _2, + "musica": _2, + "natural": _2, + "nombre": _2, + "noticias": _2, + "patria": _2, + "politica": _2, + "profesional": _2, + "plurinacional": _2, + "pueblo": _2, + "revista": _2, + "salud": _2, + "tecnologia": _2, + "tksat": _2, + "transporte": _2, + "wiki": _2 + }], + "br": [1, { + "9guacu": _2, + "abc": _2, + "adm": _2, + "adv": _2, + "agr": _2, + "aju": _2, + "am": _2, + "anani": _2, + "aparecida": _2, + "app": _2, + "arq": _2, + "art": _2, + "ato": _2, + "b": _2, + "barueri": _2, + "belem": _2, + "bhz": _2, + "bib": _2, + "bio": _2, + "blog": _2, + "bmd": _2, + "boavista": _2, + "bsb": _2, + "campinagrande": _2, + "campinas": _2, + "caxias": _2, + "cim": _2, + "cng": _2, + "cnt": _2, + "com": [1, { + "blogspot": _3, + "simplesite": _3 + }], + "contagem": _2, + "coop": _2, + "coz": _2, + "cri": _2, + "cuiaba": _2, + "curitiba": _2, + "def": _2, + "des": _2, + "det": _2, + "dev": _2, + "ecn": _2, + "eco": _2, + "edu": _2, + "emp": _2, + "enf": _2, + "eng": _2, + "esp": _2, + "etc": _2, + "eti": _2, + "far": _2, + "feira": _2, + "flog": _2, + "floripa": _2, + "fm": _2, + "fnd": _2, + "fortal": _2, + "fot": _2, + "foz": _2, + "fst": _2, + "g12": _2, + "geo": _2, + "ggf": _2, + "goiania": _2, + "gov": [1, { + "ac": _2, + "al": _2, + "am": _2, + "ap": _2, + "ba": _2, + "ce": _2, + "df": _2, + "es": _2, + "go": _2, + "ma": _2, + "mg": _2, + "ms": _2, + "mt": _2, + "pa": _2, + "pb": _2, + "pe": _2, + "pi": _2, + "pr": _2, + "rj": _2, + "rn": _2, + "ro": _2, + "rr": _2, + "rs": _2, + "sc": _2, + "se": _2, + "sp": _2, + "to": _2 + }], + "gru": _2, + "imb": _2, + "ind": _2, + "inf": _2, + "jab": _2, + "jampa": _2, + "jdf": _2, + "joinville": _2, + "jor": _2, + "jus": _2, + "leg": [1, { + "ac": _3, + "al": _3, + "am": _3, + "ap": _3, + "ba": _3, + "ce": _3, + "df": _3, + "es": _3, + "go": _3, + "ma": _3, + "mg": _3, + "ms": _3, + "mt": _3, + "pa": _3, + "pb": _3, + "pe": _3, + "pi": _3, + "pr": _3, + "rj": _3, + "rn": _3, + "ro": _3, + "rr": _3, + "rs": _3, + "sc": _3, + "se": _3, + "sp": _3, + "to": _3 + }], + "lel": _2, + "log": _2, + "londrina": _2, + "macapa": _2, + "maceio": _2, + "manaus": _2, + "maringa": _2, + "mat": _2, + "med": _2, + "mil": _2, + "morena": _2, + "mp": _2, + "mus": _2, + "natal": _2, + "net": _2, + "niteroi": _2, + "nom": _13, + "not": _2, + "ntr": _2, + "odo": _2, + "ong": _2, + "org": _2, + "osasco": _2, + "palmas": _2, + "poa": _2, + "ppg": _2, + "pro": _2, + "psc": _2, + "psi": _2, + "pvh": _2, + "qsl": _2, + "radio": _2, + "rec": _2, + "recife": _2, + "rep": _2, + "ribeirao": _2, + "rio": _2, + "riobranco": _2, + "riopreto": _2, + "salvador": _2, + "sampa": _2, + "santamaria": _2, + "santoandre": _2, + "saobernardo": _2, + "saogonca": _2, + "seg": _2, + "sjc": _2, + "slg": _2, + "slz": _2, + "sorocaba": _2, + "srv": _2, + "taxi": _2, + "tc": _2, + "tec": _2, + "teo": _2, + "the": _2, + "tmp": _2, + "trd": _2, + "tur": _2, + "tv": _2, + "udi": _2, + "vet": _2, + "vix": _2, + "vlog": _2, + "wiki": _2, + "zlg": _2 + }], + "bs": [1, { + "com": _2, + "net": _2, + "org": _2, + "edu": _2, + "gov": _2, + "we": _3 + }], + "bt": _4, + "bv": _2, + "bw": [1, { + "co": _2, + "org": _2 + }], + "by": [1, { + "gov": _2, + "mil": _2, + "com": _7, + "of": _2, + "mycloud": _3, + "mediatech": _3 + }], + "bz": [1, { + "com": _2, + "net": _2, + "org": _2, + "edu": _2, + "gov": _2, + "za": _3, + "gsj": _3 + }], + "ca": [1, { + "ab": _2, + "bc": _2, + "mb": _2, + "nb": _2, + "nf": _2, + "nl": _2, + "ns": _2, + "nt": _2, + "nu": _2, + "on": _2, + "pe": _2, + "qc": _2, + "sk": _2, + "yk": _2, + "gc": _2, + "barsy": _3, + "awdev": _5, + "co": _3, + "blogspot": _3, + "no-ip": _3, + "myspreadshop": _3 + }], + "cat": _2, + "cc": [1, { + "cloudns": _3, + "ftpaccess": _3, + "game-server": _3, + "myphotos": _3, + "scrapping": _3, + "twmail": _3, + "csx": _3, + "fantasyleague": _3, + "spawn": [0, { + "instances": _3 + }] + }], + "cd": _8, + "cf": _7, + "cg": _2, + "ch": [1, { + "square7": _3, + "blogspot": _3, + "flow": [0, { + "ae": [0, { + "alp1": _3 + }], + "appengine": _3 + }], + "linkyard-cloud": _3, + "dnsking": _3, + "gotdns": _3, + "123website": _3, + "myspreadshop": _3, + "firenet": [0, { + "*": _3, + "svc": _5 + }], + "12hp": _3, + "2ix": _3, + "4lima": _3, + "lima-city": _3 + }], + "ci": [1, { + "org": _2, + "or": _2, + "com": _2, + "co": _2, + "edu": _2, + "ed": _2, + "ac": _2, + "net": _2, + "go": _2, + "asso": _2, + "xn--aroport-bya": _2, + "aéroport": _2, + "int": _2, + "presse": _2, + "md": _2, + "gouv": _2, + "fin": _3, + "nl": _3 + }], + "ck": _13, + "cl": [1, { + "co": _2, + "gob": _2, + "gov": _2, + "mil": _2, + "blogspot": _3 + }], + "cm": [1, { + "co": _2, + "com": _2, + "gov": _2, + "net": _2 + }], + "cn": [1, { + "ac": _2, + "com": [1, { + "amazonaws": [0, { + "cn-north-1": [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _18, + "s3": _3, + "s3-accesspoint": _3, + "s3-deprecated": _3, + "s3-object-lambda": _3, + "s3-website": _3 + }], + "cn-northwest-1": _20, + "compute": _5, + "airflow": [0, { + "cn-north-1": _5, + "cn-northwest-1": _5 + }], + "eb": [0, { + "cn-north-1": _3, + "cn-northwest-1": _3 + }], + "elb": _5 + }], + "sagemaker": [0, { + "cn-north-1": _9, + "cn-northwest-1": _9 + }] + }], + "edu": _2, + "gov": _2, + "net": _2, + "org": _2, + "mil": _2, + "xn--55qx5d": _2, + "å…¬å¸": _2, + "xn--io0a7i": _2, + "网络": _2, + "xn--od0alg": _2, + "網絡": _2, + "ah": _2, + "bj": _2, + "cq": _2, + "fj": _2, + "gd": _2, + "gs": _2, + "gz": _2, + "gx": _2, + "ha": _2, + "hb": _2, + "he": _2, + "hi": _2, + "hl": _2, + "hn": _2, + "jl": _2, + "js": _2, + "jx": _2, + "ln": _2, + "nm": _2, + "nx": _2, + "qh": _2, + "sc": _2, + "sd": _2, + "sh": _2, + "sn": _2, + "sx": _2, + "tj": _2, + "xj": _2, + "xz": _2, + "yn": _2, + "zj": _2, + "hk": _2, + "mo": _2, + "tw": _2, + "canva-apps": _3, + "canvasite": _17, + "instantcloud": _3, + "quickconnect": _21 + }], + "co": [1, { + "arts": _2, + "com": _7, + "edu": _2, + "firm": _2, + "gov": _2, + "info": _2, + "int": _2, + "mil": _2, + "net": _2, + "nom": _2, + "org": _2, + "rec": _2, + "web": _2, + "carrd": _3, + "crd": _3, + "otap": _5, + "leadpages": _3, + "lpages": _3, + "mypi": _3, + "n4t": _3, + "firewalledreplit": _6, + "repl": _6, + "supabase": _3 + }], + "com": [1, { + "a2hosted": _3, + "cpserver": _3, + "devcdnaccesso": _5, + "adobeaemcloud": [2, { + "dev": _5 + }], + "airkitapps": _3, + "airkitapps-au": _3, + "aivencloud": _3, + "kasserver": _3, + "amazonaws": [0, { + "af-south-1": _24, + "ap-east-1": _25, + "ap-northeast-1": _26, + "ap-northeast-2": _26, + "ap-northeast-3": _24, + "ap-south-1": _26, + "ap-south-2": _27, + "ap-southeast-1": _26, + "ap-southeast-2": _26, + "ap-southeast-3": _20, + "ap-southeast-4": _27, + "ca-central-1": _29, + "ca-west-1": [0, { + "execute-api": _3, + "dualstack": _28, + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-fips": _3, + "s3-website": _3 + }], + "eu-central-1": _26, + "eu-central-2": _27, + "eu-north-1": _25, + "eu-south-1": _24, + "eu-south-2": _27, + "eu-west-1": [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _18, + "s3": _3, + "s3-accesspoint": _3, + "s3-deprecated": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "analytics-gateway": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + "eu-west-2": _25, + "eu-west-3": _24, + "il-central-1": [0, { + "execute-api": _3, + "dualstack": _19, + "s3": _3, + "s3-accesspoint": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "aws-cloud9": _22, + "cloud9": [0, { + "vfs": _3 + }] + }], + "me-central-1": _20, + "me-south-1": _25, + "sa-east-1": _24, + "us-east-1": [2, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _28, + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-deprecated": _3, + "s3-fips": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "analytics-gateway": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + "us-east-2": [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _30, + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-deprecated": _3, + "s3-fips": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "analytics-gateway": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + "us-gov-east-1": _31, + "us-gov-west-1": _31, + "us-west-1": _29, + "us-west-2": [0, { + "execute-api": _3, + "emrappui-prod": _3, + "emrnotebooks-prod": _3, + "emrstudio-prod": _3, + "dualstack": _28, + "s3": _3, + "s3-accesspoint": _3, + "s3-accesspoint-fips": _3, + "s3-deprecated": _3, + "s3-fips": _3, + "s3-object-lambda": _3, + "s3-website": _3, + "analytics-gateway": _3, + "aws-cloud9": _22, + "cloud9": _23 + }], + "compute": _5, + "compute-1": _5, + "airflow": [0, { + "ap-northeast-1": _5, + "ap-northeast-2": _5, + "ap-south-1": _5, + "ap-southeast-1": _5, + "ap-southeast-2": _5, + "ca-central-1": _5, + "eu-central-1": _5, + "eu-north-1": _5, + "eu-west-1": _5, + "eu-west-2": _5, + "eu-west-3": _5, + "sa-east-1": _5, + "us-east-1": _5, + "us-east-2": _5, + "us-west-2": _5 + }], + "s3": _3, + "s3-1": _3, + "s3-ap-east-1": _3, + "s3-ap-northeast-1": _3, + "s3-ap-northeast-2": _3, + "s3-ap-northeast-3": _3, + "s3-ap-south-1": _3, + "s3-ap-southeast-1": _3, + "s3-ap-southeast-2": _3, + "s3-ca-central-1": _3, + "s3-eu-central-1": _3, + "s3-eu-north-1": _3, + "s3-eu-west-1": _3, + "s3-eu-west-2": _3, + "s3-eu-west-3": _3, + "s3-external-1": _3, + "s3-fips-us-gov-east-1": _3, + "s3-fips-us-gov-west-1": _3, + "s3-global": [0, { + "accesspoint": [0, { + "mrap": _3 + }] + }], + "s3-me-south-1": _3, + "s3-sa-east-1": _3, + "s3-us-east-2": _3, + "s3-us-gov-east-1": _3, + "s3-us-gov-west-1": _3, + "s3-us-west-1": _3, + "s3-us-west-2": _3, + "s3-website-ap-northeast-1": _3, + "s3-website-ap-southeast-1": _3, + "s3-website-ap-southeast-2": _3, + "s3-website-eu-west-1": _3, + "s3-website-sa-east-1": _3, + "s3-website-us-east-1": _3, + "s3-website-us-gov-west-1": _3, + "s3-website-us-west-1": _3, + "s3-website-us-west-2": _3, + "elb": _5 + }], + "amazoncognito": [0, { + "af-south-1": _32, + "ap-northeast-1": _32, + "ap-northeast-2": _32, + "ap-northeast-3": _32, + "ap-south-1": _32, + "ap-southeast-1": _32, + "ap-southeast-2": _32, + "ap-southeast-3": _32, + "ca-central-1": _32, + "eu-central-1": _32, + "eu-north-1": _32, + "eu-south-1": _32, + "eu-west-1": _32, + "eu-west-2": _32, + "eu-west-3": _32, + "il-central-1": _32, + "me-south-1": _32, + "sa-east-1": _32, + "us-east-1": _33, + "us-east-2": _33, + "us-gov-west-1": [0, { + "auth-fips": _3 + }], + "us-west-1": _33, + "us-west-2": _33 + }], + "amplifyapp": _5, + "awsapprunner": _5, + "elasticbeanstalk": [2, { + "af-south-1": _3, + "ap-east-1": _3, + "ap-northeast-1": _3, + "ap-northeast-2": _3, + "ap-northeast-3": _3, + "ap-south-1": _3, + "ap-southeast-1": _3, + "ap-southeast-2": _3, + "ap-southeast-3": _3, + "ca-central-1": _3, + "eu-central-1": _3, + "eu-north-1": _3, + "eu-south-1": _3, + "eu-west-1": _3, + "eu-west-2": _3, + "eu-west-3": _3, + "il-central-1": _3, + "me-south-1": _3, + "sa-east-1": _3, + "us-east-1": _3, + "us-east-2": _3, + "us-gov-east-1": _3, + "us-gov-west-1": _3, + "us-west-1": _3, + "us-west-2": _3 + }], + "awsglobalaccelerator": _3, + "siiites": _3, + "appspacehosted": _3, + "appspaceusercontent": _3, + "on-aptible": _3, + "myasustor": _3, + "balena-devices": _3, + "betainabox": _3, + "boutir": _3, + "bplaced": _3, + "cafjs": _3, + "canva-apps": _3, + "br": _3, + "cn": _3, + "de": _3, + "eu": _3, + "jpn": _3, + "mex": _3, + "ru": _3, + "sa": _3, + "uk": _3, + "us": _3, + "za": _3, + "ar": _3, + "hu": _3, + "kr": _3, + "no": _3, + "qc": _3, + "uy": _3, + "africa": _3, + "gr": _3, + "co": _3, + "jdevcloud": _3, + "wpdevcloud": _3, + "cloudcontrolled": _3, + "cloudcontrolapp": _3, + "cf-ipfs": _3, + "cloudflare-ipfs": _3, + "trycloudflare": _3, + "cprapid": _5, + "customer-oci": [0, { + "*": _3, + "oci": _5, + "ocp": _5, + "ocs": _5 + }], + "cyclic-app": _3, + "dattolocal": _3, + "dattorelay": _3, + "dattoweb": _3, + "mydatto": _3, + "builtwithdark": _3, + "datadetect": [0, { + "demo": _3, + "instance": _3 + }], + "ddns5": _3, + "discordsays": _3, + "discordsez": _3, + "drayddns": _3, + "dreamhosters": _3, + "mydrobo": _3, + "dyndns-at-home": _3, + "dyndns-at-work": _3, + "dyndns-blog": _3, + "dyndns-free": _3, + "dyndns-home": _3, + "dyndns-ip": _3, + "dyndns-mail": _3, + "dyndns-office": _3, + "dyndns-pics": _3, + "dyndns-remote": _3, + "dyndns-server": _3, + "dyndns-web": _3, + "dyndns-wiki": _3, + "dyndns-work": _3, + "blogdns": _3, + "cechire": _3, + "dnsalias": _3, + "dnsdojo": _3, + "doesntexist": _3, + "dontexist": _3, + "doomdns": _3, + "dyn-o-saur": _3, + "dynalias": _3, + "est-a-la-maison": _3, + "est-a-la-masion": _3, + "est-le-patron": _3, + "est-mon-blogueur": _3, + "from-ak": _3, + "from-al": _3, + "from-ar": _3, + "from-ca": _3, + "from-ct": _3, + "from-dc": _3, + "from-de": _3, + "from-fl": _3, + "from-ga": _3, + "from-hi": _3, + "from-ia": _3, + "from-id": _3, + "from-il": _3, + "from-in": _3, + "from-ks": _3, + "from-ky": _3, + "from-ma": _3, + "from-md": _3, + "from-mi": _3, + "from-mn": _3, + "from-mo": _3, + "from-ms": _3, + "from-mt": _3, + "from-nc": _3, + "from-nd": _3, + "from-ne": _3, + "from-nh": _3, + "from-nj": _3, + "from-nm": _3, + "from-nv": _3, + "from-oh": _3, + "from-ok": _3, + "from-or": _3, + "from-pa": _3, + "from-pr": _3, + "from-ri": _3, + "from-sc": _3, + "from-sd": _3, + "from-tn": _3, + "from-tx": _3, + "from-ut": _3, + "from-va": _3, + "from-vt": _3, + "from-wa": _3, + "from-wi": _3, + "from-wv": _3, + "from-wy": _3, + "getmyip": _3, + "gotdns": _3, + "hobby-site": _3, + "homelinux": _3, + "homeunix": _3, + "iamallama": _3, + "is-a-anarchist": _3, + "is-a-blogger": _3, + "is-a-bookkeeper": _3, + "is-a-bulls-fan": _3, + "is-a-caterer": _3, + "is-a-chef": _3, + "is-a-conservative": _3, + "is-a-cpa": _3, + "is-a-cubicle-slave": _3, + "is-a-democrat": _3, + "is-a-designer": _3, + "is-a-doctor": _3, + "is-a-financialadvisor": _3, + "is-a-geek": _3, + "is-a-green": _3, + "is-a-guru": _3, + "is-a-hard-worker": _3, + "is-a-hunter": _3, + "is-a-landscaper": _3, + "is-a-lawyer": _3, + "is-a-liberal": _3, + "is-a-libertarian": _3, + "is-a-llama": _3, + "is-a-musician": _3, + "is-a-nascarfan": _3, + "is-a-nurse": _3, + "is-a-painter": _3, + "is-a-personaltrainer": _3, + "is-a-photographer": _3, + "is-a-player": _3, + "is-a-republican": _3, + "is-a-rockstar": _3, + "is-a-socialist": _3, + "is-a-student": _3, + "is-a-teacher": _3, + "is-a-techie": _3, + "is-a-therapist": _3, + "is-an-accountant": _3, + "is-an-actor": _3, + "is-an-actress": _3, + "is-an-anarchist": _3, + "is-an-artist": _3, + "is-an-engineer": _3, + "is-an-entertainer": _3, + "is-certified": _3, + "is-gone": _3, + "is-into-anime": _3, + "is-into-cars": _3, + "is-into-cartoons": _3, + "is-into-games": _3, + "is-leet": _3, + "is-not-certified": _3, + "is-slick": _3, + "is-uberleet": _3, + "is-with-theband": _3, + "isa-geek": _3, + "isa-hockeynut": _3, + "issmarterthanyou": _3, + "likes-pie": _3, + "likescandy": _3, + "neat-url": _3, + "saves-the-whales": _3, + "selfip": _3, + "sells-for-less": _3, + "sells-for-u": _3, + "servebbs": _3, + "simple-url": _3, + "space-to-rent": _3, + "teaches-yoga": _3, + "writesthisblog": _3, + "digitaloceanspaces": _5, + "ddnsfree": _3, + "ddnsgeek": _3, + "giize": _3, + "gleeze": _3, + "kozow": _3, + "loseyourip": _3, + "ooguy": _3, + "theworkpc": _3, + "mytuleap": _3, + "tuleap-partners": _3, + "encoreapi": _3, + "evennode": [0, { + "eu-1": _3, + "eu-2": _3, + "eu-3": _3, + "eu-4": _3, + "us-1": _3, + "us-2": _3, + "us-3": _3, + "us-4": _3 + }], + "onfabrica": _3, + "fastly-edge": _3, + "fastly-terrarium": _3, + "fastvps-server": _3, + "mydobiss": _3, + "firebaseapp": _3, + "fldrv": _3, + "forgeblocks": _3, + "framercanvas": _3, + "freebox-os": _3, + "freeboxos": _3, + "freemyip": _3, + "aliases121": _3, + "gentapps": _3, + "gentlentapis": _3, + "githubusercontent": _3, + "0emm": _5, + "appspot": [2, { + "r": _5 + }], + "codespot": _3, + "googleapis": _3, + "googlecode": _3, + "pagespeedmobilizer": _3, + "publishproxy": _3, + "withgoogle": _3, + "withyoutube": _3, + "blogspot": _3, + "awsmppl": _3, + "herokuapp": _3, + "herokussl": _3, + "impertrixcdn": _3, + "impertrix": _3, + "smushcdn": _3, + "wphostedmail": _3, + "wpmucdn": _3, + "pixolino": _3, + "amscompute": _3, + "dopaas": _3, + "hosted-by-previder": _35, + "hosteur": [0, { + "rag-cloud": _3, + "rag-cloud-ch": _3 + }], + "ik-server": [0, { + "jcloud": _3, + "jcloud-ver-jpc": _3 + }], + "jelastic": [0, { + "demo": _3 + }], + "kilatiron": _3, + "massivegrid": _35, + "wafaicloud": [0, { + "jed": _3, + "lon": _3, + "ryd": _3 + }], + "joyent": [0, { + "cns": _5 + }], + "ktistory": _3, + "lpusercontent": _3, + "lmpm": _36, + "linode": [0, { + "members": _3, + "nodebalancer": _5 + }], + "linodeobjects": _5, + "linodeusercontent": [0, { + "ip": _3 + }], + "barsycenter": _3, + "barsyonline": _3, + "mazeplay": _3, + "miniserver": _3, + "atmeta": _3, + "fbsbx": _34, + "meteorapp": _37, + "azure": [0, { + "cloudapp": _5 + }], + "hostedpi": _3, + "mythic-beasts": [0, { + "customer": _3, + "caracal": _3, + "fentiger": _3, + "lynx": _3, + "ocelot": _3, + "oncilla": _3, + "onza": _3, + "sphinx": _3, + "vs": _3, + "x": _3, + "yali": _3 + }], + "nospamproxy": _14, + "4u": _3, + "nfshost": _3, + "001www": _3, + "ddnslive": _3, + "myiphost": _3, + "blogsyte": _3, + "ciscofreak": _3, + "damnserver": _3, + "ditchyourip": _3, + "dnsiskinky": _3, + "dynns": _3, + "geekgalaxy": _3, + "health-carereform": _3, + "homesecuritymac": _3, + "homesecuritypc": _3, + "myactivedirectory": _3, + "mysecuritycamera": _3, + "net-freaks": _3, + "onthewifi": _3, + "point2this": _3, + "quicksytes": _3, + "securitytactics": _3, + "serveexchange": _3, + "servehumour": _3, + "servep2p": _3, + "servesarcasm": _3, + "stufftoread": _3, + "unusualperson": _3, + "workisboring": _3, + "3utilities": _3, + "ddnsking": _3, + "myvnc": _3, + "servebeer": _3, + "servecounterstrike": _3, + "serveftp": _3, + "servegame": _3, + "servehalflife": _3, + "servehttp": _3, + "serveirc": _3, + "servemp3": _3, + "servepics": _3, + "servequake": _3, + "observableusercontent": [0, { + "static": _3 + }], + "simplesite": _3, + "orsites": _3, + "operaunite": _3, + "authgear-staging": _3, + "authgearapps": _3, + "skygearapp": _3, + "outsystemscloud": _3, + "ownprovider": _3, + "pgfog": _3, + "pagefrontapp": _3, + "pagexl": _3, + "paywhirl": _5, + "gotpantheon": _3, + "upsunapp": _3, + "platter-app": _3, + "pleskns": _3, + "postman-echo": _3, + "prgmr": [0, { + "xen": _3 + }], + "pythonanywhere": _37, + "qualifioapp": _3, + "ladesk": _3, + "qbuser": _3, + "qa2": _3, + "dev-myqnapcloud": _3, + "alpha-myqnapcloud": _3, + "myqnapcloud": _3, + "quipelements": _5, + "rackmaze": _3, + "rhcloud": _3, + "render": _36, + "onrender": _3, + "180r": _3, + "dojin": _3, + "sakuratan": _3, + "sakuraweb": _3, + "x0": _3, + "code": [0, { + "builder": _5, + "dev-builder": _5, + "stg-builder": _5 + }], + "salesforce": [0, { + "platform": [0, { + "code-builder-stg": [0, { + "test": [0, { + "001": _5 + }] + }] + }] + }], + "logoip": _3, + "scrysec": _3, + "firewall-gateway": _3, + "myshopblocks": _3, + "myshopify": _3, + "shopitsite": _3, + "1kapp": _3, + "appchizi": _3, + "applinzi": _3, + "sinaapp": _3, + "vipsinaapp": _3, + "bounty-full": [2, { + "alpha": _3, + "beta": _3 + }], + "streamlitapp": _3, + "try-snowplow": _3, + "stackhero-network": _3, + "playstation-cloud": _3, + "myspreadshop": _3, + "stdlib": [0, { + "api": _3 + }], + "streak-link": _3, + "streaklinks": _3, + "streakusercontent": _3, + "temp-dns": _3, + "dsmynas": _3, + "familyds": _3, + "mytabit": _3, + "tb-hosting": _38, + "reservd": _3, + "thingdustdata": _3, + "bloxcms": _3, + "townnews-staging": _3, + "typeform": [0, { + "pro": _3 + }], + "hk": _3, + "it": _3, + "vultrobjects": _5, + "wafflecell": _3, + "reserve-online": _3, + "hotelwithflight": _3, + "remotewd": _3, + "wiardweb": _39, + "messwithdns": _3, + "woltlab-demo": _3, + "wpenginepowered": [2, { + "js": _3 + }], + "wixsite": _3, + "xnbay": [2, { + "u2": _3, + "u2-local": _3 + }], + "yolasite": _3 + }], + "coop": _2, + "cr": [1, { + "ac": _2, + "co": _2, + "ed": _2, + "fi": _2, + "go": _2, + "or": _2, + "sa": _2 + }], + "cu": [1, { + "com": _2, + "edu": _2, + "org": _2, + "net": _2, + "gov": _2, + "inf": _2 + }], + "cv": [1, { + "com": _2, + "edu": _2, + "int": _2, + "nome": _2, + "org": _2, + "blogspot": _3 + }], + "cw": _40, + "cx": [1, { + "gov": _2, + "ath": _3, + "info": _3, + "assessments": _3, + "calculators": _3, + "funnels": _3, + "paynow": _3, + "quizzes": _3, + "researched": _3, + "tests": _3 + }], + "cy": [1, { + "ac": _2, + "biz": _2, + "com": [1, { + "blogspot": _3, + "scaleforce": _41 + }], + "ekloges": _2, + "gov": _2, + "ltd": _2, + "mil": _2, + "net": _2, + "org": _2, + "press": _2, + "pro": _2, + "tm": _2 + }], + "cz": [1, { + "co": _3, + "realm": _3, + "e4": _3, + "blogspot": _3, + "metacentrum": [0, { + "cloud": _5, + "custom": _3 + }], + "muni": [0, { + "cloud": [0, { + "flt": _3, + "usr": _3 + }] + }] + }], + "de": [1, { + "bplaced": _3, + "square7": _3, + "com": _3, + "cosidns": [0, { + "dyn": _3 + }], + "dynamisches-dns": _3, + "dnsupdater": _3, + "internet-dns": _3, + "l-o-g-i-n": _3, + "dnshome": _3, + "fuettertdasnetz": _3, + "isteingeek": _3, + "istmein": _3, + "lebtimnetz": _3, + "leitungsen": _3, + "traeumtgerade": _3, + "ddnss": [2, { + "dyn": _3, + "dyndns": _3 + }], + "dyndns1": _3, + "dyn-ip24": _3, + "home-webserver": [2, { + "dyn": _3 + }], + "myhome-server": _3, + "frusky": _5, + "goip": _3, + "blogspot": _3, + "xn--gnstigbestellen-zvb": _3, + "günstigbestellen": _3, + "xn--gnstigliefern-wob": _3, + "günstigliefern": _3, + "hs-heilbronn": [0, { + "it": _39 + }], + "dyn-berlin": _3, + "in-berlin": _3, + "in-brb": _3, + "in-butter": _3, + "in-dsl": _3, + "in-vpn": _3, + "iservschule": _3, + "mein-iserv": _3, + "schulplattform": _3, + "schulserver": _3, + "test-iserv": _3, + "keymachine": _3, + "git-repos": _3, + "lcube-server": _3, + "svn-repos": _3, + "barsy": _3, + "123webseite": _3, + "logoip": _3, + "firewall-gateway": _3, + "my-gateway": _3, + "my-router": _3, + "spdns": _3, + "speedpartner": [0, { + "customer": _3 + }], + "myspreadshop": _3, + "taifun-dns": _3, + "12hp": _3, + "2ix": _3, + "4lima": _3, + "lima-city": _3, + "dd-dns": _3, + "dray-dns": _3, + "draydns": _3, + "dyn-vpn": _3, + "dynvpn": _3, + "mein-vigor": _3, + "my-vigor": _3, + "my-wan": _3, + "syno-ds": _3, + "synology-diskstation": _3, + "synology-ds": _3, + "uberspace": _5, + "virtualuser": _3, + "virtual-user": _3, + "community-pro": _3, + "diskussionsbereich": _3 + }], + "dj": _2, + "dk": [1, { + "biz": _3, + "co": _3, + "firm": _3, + "reg": _3, + "store": _3, + "blogspot": _3, + "123hjemmeside": _3, + "myspreadshop": _3 + }], + "dm": _4, + "do": [1, { + "art": _2, + "com": _2, + "edu": _2, + "gob": _2, + "gov": _2, + "mil": _2, + "net": _2, + "org": _2, + "sld": _2, + "web": _2 + }], + "dz": [1, { + "art": _2, + "asso": _2, + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "net": _2, + "pol": _2, + "soc": _2, + "tm": _2 + }], + "ec": [1, { + "com": _2, + "info": _2, + "net": _2, + "fin": _2, + "k12": _2, + "med": _2, + "pro": _2, + "org": _2, + "edu": _2, + "gov": _2, + "gob": _2, + "mil": _2, + "base": _3, + "official": _3 + }], + "edu": [1, { + "rit": [0, { + "git-pages": _3 + }] + }], + "ee": [1, { + "edu": _2, + "gov": _2, + "riik": _2, + "lib": _2, + "med": _2, + "com": _7, + "pri": _2, + "aip": _2, + "org": _2, + "fie": _2 + }], + "eg": [1, { + "com": _7, + "edu": _2, + "eun": _2, + "gov": _2, + "mil": _2, + "name": _2, + "net": _2, + "org": _2, + "sci": _2 + }], + "er": _13, + "es": [1, { + "com": _7, + "nom": _2, + "org": _2, + "gob": _2, + "edu": _2, + "123miweb": _3, + "myspreadshop": _3 + }], + "et": [1, { + "com": _2, + "gov": _2, + "org": _2, + "edu": _2, + "biz": _2, + "name": _2, + "info": _2, + "net": _2 + }], + "eu": [1, { + "airkitapps": _3, + "mycd": _3, + "cloudns": _3, + "dogado": _42, + "barsy": _3, + "wellbeingzone": _3, + "spdns": _3, + "transurl": _5, + "diskstation": _3 + }], + "fi": [1, { + "aland": _2, + "dy": _3, + "blogspot": _3, + "xn--hkkinen-5wa": _3, + "häkkinen": _3, + "iki": _3, + "cloudplatform": [0, { + "fi": _3 + }], + "datacenter": [0, { + "demo": _3, + "paas": _3 + }], + "kapsi": _3, + "123kotisivu": _3, + "myspreadshop": _3 + }], + "fj": [1, { + "ac": _2, + "biz": _2, + "com": _2, + "gov": _2, + "info": _2, + "mil": _2, + "name": _2, + "net": _2, + "org": _2, + "pro": _2 + }], + "fk": _13, + "fm": [1, { + "com": _2, + "edu": _2, + "net": _2, + "org": _2, + "radio": _3, + "user": _5 + }], + "fo": _2, + "fr": [1, { + "asso": _2, + "com": _2, + "gouv": _2, + "nom": _2, + "prd": _2, + "tm": _2, + "avoues": _2, + "cci": _2, + "greta": _2, + "huissier-justice": _2, + "en-root": _3, + "fbx-os": _3, + "fbxos": _3, + "freebox-os": _3, + "freeboxos": _3, + "blogspot": _3, + "goupile": _3, + "123siteweb": _3, + "on-web": _3, + "chirurgiens-dentistes-en-france": _3, + "dedibox": _3, + "aeroport": _3, + "avocat": _3, + "chambagri": _3, + "chirurgiens-dentistes": _3, + "experts-comptables": _3, + "medecin": _3, + "notaires": _3, + "pharmacien": _3, + "port": _3, + "veterinaire": _3, + "myspreadshop": _3, + "ynh": _3 + }], + "ga": _2, + "gb": _2, + "gd": [1, { + "edu": _2, + "gov": _2 + }], + "ge": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "mil": _2, + "net": _2, + "pvt": _2 + }], + "gf": _2, + "gg": [1, { + "co": _2, + "net": _2, + "org": _2, + "kaas": _3, + "cya": _3, + "stackit": _3, + "panel": [2, { + "daemon": _3 + }] + }], + "gh": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "mil": _2 + }], + "gi": [1, { + "com": _2, + "ltd": _2, + "gov": _2, + "mod": _2, + "edu": _2, + "org": _2 + }], + "gl": [1, { + "co": _2, + "com": _2, + "edu": _2, + "net": _2, + "org": _2, + "biz": _3, + "xx": _3 + }], + "gm": _2, + "gn": [1, { + "ac": _2, + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "net": _2 + }], + "gov": _2, + "gp": [1, { + "com": _2, + "net": _2, + "mobi": _2, + "edu": _2, + "org": _2, + "asso": _2, + "app": _3 + }], + "gq": _2, + "gr": [1, { + "com": _2, + "edu": _2, + "net": _2, + "org": _2, + "gov": _2, + "blogspot": _3, + "simplesite": _3 + }], + "gs": _2, + "gt": [1, { + "com": _2, + "edu": _2, + "gob": _2, + "ind": _2, + "mil": _2, + "net": _2, + "org": _2, + "blog": _3, + "de": _3, + "to": _3 + }], + "gu": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "guam": _2, + "info": _2, + "net": _2, + "org": _2, + "web": _2 + }], + "gw": _2, + "gy": [1, { + "co": _2, + "com": _2, + "edu": _2, + "gov": _2, + "net": _2, + "org": _2, + "be": _3 + }], + "hk": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "idv": _2, + "net": _2, + "org": _2, + "xn--55qx5d": _2, + "å…¬å¸": _2, + "xn--wcvs22d": _2, + "教育": _2, + "xn--lcvr32d": _2, + "敎育": _2, + "xn--mxtq1m": _2, + "政府": _2, + "xn--gmqw5a": _2, + "個人": _2, + "xn--ciqpn": _2, + "个人": _2, + "xn--gmq050i": _2, + "箇人": _2, + "xn--zf0avx": _2, + "網络": _2, + "xn--io0a7i": _2, + "网络": _2, + "xn--mk0axi": _2, + "组織": _2, + "xn--od0alg": _2, + "網絡": _2, + "xn--od0aq3b": _2, + "网絡": _2, + "xn--tn0ag": _2, + "组织": _2, + "xn--uc0atv": _2, + "組織": _2, + "xn--uc0ay4a": _2, + "組织": _2, + "blogspot": _3, + "secaas": _3, + "ltd": _3, + "inc": _3 + }], + "hm": _2, + "hn": [1, { + "com": _2, + "edu": _2, + "org": _2, + "net": _2, + "mil": _2, + "gob": _2, + "cc": _3 + }], + "hr": [1, { + "iz": _2, + "from": _2, + "name": _2, + "com": _2, + "blogspot": _3, + "free": _3 + }], + "ht": [1, { + "com": _2, + "shop": _2, + "firm": _2, + "info": _2, + "adult": _2, + "net": _2, + "pro": _2, + "org": _2, + "med": _2, + "art": _2, + "coop": _2, + "pol": _2, + "asso": _2, + "edu": _2, + "rel": _2, + "gouv": _2, + "perso": _2 + }], + "hu": [1, { + "2000": _2, + "co": _2, + "info": _2, + "org": _2, + "priv": _2, + "sport": _2, + "tm": _2, + "agrar": _2, + "bolt": _2, + "casino": _2, + "city": _2, + "erotica": _2, + "erotika": _2, + "film": _2, + "forum": _2, + "games": _2, + "hotel": _2, + "ingatlan": _2, + "jogasz": _2, + "konyvelo": _2, + "lakas": _2, + "media": _2, + "news": _2, + "reklam": _2, + "sex": _2, + "shop": _2, + "suli": _2, + "szex": _2, + "tozsde": _2, + "utazas": _2, + "video": _2, + "blogspot": _3 + }], + "id": [1, { + "ac": _2, + "biz": _2, + "co": _7, + "desa": _2, + "go": _2, + "mil": _2, + "my": [1, { + "rss": _5 + }], + "net": _2, + "or": _2, + "ponpes": _2, + "sch": _2, + "web": _2, + "flap": _3, + "forte": _3 + }], + "ie": [1, { + "gov": _2, + "blogspot": _3, + "myspreadshop": _3 + }], + "il": [1, { + "ac": _2, + "co": [1, { + "ravpage": _3, + "blogspot": _3, + "tabitorder": _3, + "mytabit": _3 + }], + "gov": _2, + "idf": _2, + "k12": _2, + "muni": _2, + "net": _2, + "org": _2 + }], + "xn--4dbrk0ce": [1, { + "xn--4dbgdty6c": _2, + "xn--5dbhl8d": _2, + "xn--8dbq2a": _2, + "xn--hebda8b": _2 + }], + "ישר×ל": [1, { + "×קדמיה": _2, + "ישוב": _2, + "צהל": _2, + "ממשל": _2 + }], + "im": [1, { + "ac": _2, + "co": [1, { + "ltd": _2, + "plc": _2 + }], + "com": _2, + "net": _2, + "org": _2, + "tt": _2, + "tv": _2, + "ro": _3 + }], + "in": [1, { + "5g": _2, + "6g": _2, + "ac": _2, + "ai": _2, + "am": _2, + "bihar": _2, + "biz": _2, + "business": _2, + "ca": _2, + "cn": _2, + "co": [1, { + "cyclic": _3 + }], + "com": _2, + "coop": _2, + "cs": _2, + "delhi": _2, + "dr": _2, + "edu": _2, + "er": _2, + "firm": _2, + "gen": _2, + "gov": _2, + "gujarat": _2, + "ind": _2, + "info": _2, + "int": _2, + "internet": _2, + "io": _2, + "me": _2, + "mil": _2, + "net": _2, + "nic": _2, + "org": _2, + "pg": _2, + "post": _2, + "pro": _2, + "res": _2, + "travel": _2, + "tv": _2, + "uk": _2, + "up": _2, + "us": _2, + "web": _3, + "cloudns": _3, + "blogspot": _3, + "barsy": _3, + "supabase": _3 + }], + "info": [1, { + "cloudns": _3, + "dynamic-dns": _3, + "dyndns": _3, + "barrel-of-knowledge": _3, + "barrell-of-knowledge": _3, + "for-our": _3, + "groks-the": _3, + "groks-this": _3, + "here-for-more": _3, + "knowsitall": _3, + "selfip": _3, + "webhop": _3, + "barsy": _3, + "mayfirst": _3, + "forumz": _3, + "nsupdate": _3, + "dvrcam": _3, + "ilovecollege": _3, + "no-ip": _3, + "dnsupdate": _3, + "v-info": _3 + }], + "int": [1, { + "eu": _2 + }], + "io": [1, { + "2038": _3, + "com": _2, + "on-acorn": _5, + "apigee": _3, + "b-data": _3, + "backplaneapp": _3, + "banzaicloud": [0, { + "app": _3, + "backyards": _5 + }], + "beagleboard": _3, + "bitbucket": _3, + "bluebite": _3, + "boxfuse": _3, + "brave": [0, { + "s": _5 + }], + "browsersafetymark": _3, + "bigv": [0, { + "uk0": _3 + }], + "cleverapps": _3, + "dappnode": [0, { + "dyndns": _3 + }], + "dedyn": _3, + "drud": _3, + "definima": _3, + "fh-muenster": _3, + "shw": _3, + "forgerock": [0, { + "id": _3 + }], + "ghost": _3, + "github": _3, + "gitlab": _3, + "lolipop": _3, + "hasura-app": _3, + "hostyhosting": _3, + "moonscale": _5, + "beebyte": _35, + "beebyteapp": [0, { + "sekd1": _3 + }], + "jele": _3, + "unispace": [0, { + "cloud-fr1": _3 + }], + "webthings": _3, + "loginline": _3, + "barsy": _3, + "azurecontainer": _5, + "ngrok": [2, { + "ap": _3, + "au": _3, + "eu": _3, + "in": _3, + "jp": _3, + "sa": _3, + "us": _3 + }], + "nodeart": [0, { + "stage": _3 + }], + "nid": _3, + "pantheonsite": _3, + "dyn53": _3, + "pstmn": [2, { + "mock": _3 + }], + "protonet": _3, + "qoto": _3, + "qcx": [2, { + "sys": _5 + }], + "vaporcloud": _3, + "vbrplsbx": [0, { + "g": _3 + }], + "on-k3s": _5, + "on-rio": _5, + "readthedocs": _3, + "resindevice": _3, + "resinstaging": [0, { + "devices": _3 + }], + "hzc": _3, + "sandcats": _3, + "shiftcrypto": _3, + "shiftedit": _3, + "mo-siemens": _3, + "musician": _3, + "lair": _34, + "stolos": _5, + "spacekit": _3, + "utwente": _3, + "s5y": _5, + "edugit": _3, + "telebit": _3, + "thingdust": [0, { + "dev": _45, + "disrec": _45, + "prod": _46, + "testing": _45 + }], + "tickets": _3, + "upli": _3, + "webflow": _3, + "webflowtest": _3, + "wedeploy": _3, + "editorx": _3, + "wixstudio": _3, + "basicserver": _3, + "virtualserver": _3 + }], + "iq": _47, + "ir": [1, { + "ac": _2, + "co": _2, + "gov": _2, + "id": _2, + "net": _2, + "org": _2, + "sch": _2, + "xn--mgba3a4f16a": _2, + "ایران": _2, + "xn--mgba3a4fra": _2, + "ايران": _2 + }], + "is": [1, { + "net": _2, + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "int": _2, + "cupcake": _3, + "blogspot": _3 + }], + "it": [1, { + "gov": _2, + "edu": _2, + "abr": _2, + "abruzzo": _2, + "aosta-valley": _2, + "aostavalley": _2, + "bas": _2, + "basilicata": _2, + "cal": _2, + "calabria": _2, + "cam": _2, + "campania": _2, + "emilia-romagna": _2, + "emiliaromagna": _2, + "emr": _2, + "friuli-v-giulia": _2, + "friuli-ve-giulia": _2, + "friuli-vegiulia": _2, + "friuli-venezia-giulia": _2, + "friuli-veneziagiulia": _2, + "friuli-vgiulia": _2, + "friuliv-giulia": _2, + "friulive-giulia": _2, + "friulivegiulia": _2, + "friulivenezia-giulia": _2, + "friuliveneziagiulia": _2, + "friulivgiulia": _2, + "fvg": _2, + "laz": _2, + "lazio": _2, + "lig": _2, + "liguria": _2, + "lom": _2, + "lombardia": _2, + "lombardy": _2, + "lucania": _2, + "mar": _2, + "marche": _2, + "mol": _2, + "molise": _2, + "piedmont": _2, + "piemonte": _2, + "pmn": _2, + "pug": _2, + "puglia": _2, + "sar": _2, + "sardegna": _2, + "sardinia": _2, + "sic": _2, + "sicilia": _2, + "sicily": _2, + "taa": _2, + "tos": _2, + "toscana": _2, + "trentin-sud-tirol": _2, + "xn--trentin-sd-tirol-rzb": _2, + "trentin-süd-tirol": _2, + "trentin-sudtirol": _2, + "xn--trentin-sdtirol-7vb": _2, + "trentin-südtirol": _2, + "trentin-sued-tirol": _2, + "trentin-suedtirol": _2, + "trentino-a-adige": _2, + "trentino-aadige": _2, + "trentino-alto-adige": _2, + "trentino-altoadige": _2, + "trentino-s-tirol": _2, + "trentino-stirol": _2, + "trentino-sud-tirol": _2, + "xn--trentino-sd-tirol-c3b": _2, + "trentino-süd-tirol": _2, + "trentino-sudtirol": _2, + "xn--trentino-sdtirol-szb": _2, + "trentino-südtirol": _2, + "trentino-sued-tirol": _2, + "trentino-suedtirol": _2, + "trentino": _2, + "trentinoa-adige": _2, + "trentinoaadige": _2, + "trentinoalto-adige": _2, + "trentinoaltoadige": _2, + "trentinos-tirol": _2, + "trentinostirol": _2, + "trentinosud-tirol": _2, + "xn--trentinosd-tirol-rzb": _2, + "trentinosüd-tirol": _2, + "trentinosudtirol": _2, + "xn--trentinosdtirol-7vb": _2, + "trentinosüdtirol": _2, + "trentinosued-tirol": _2, + "trentinosuedtirol": _2, + "trentinsud-tirol": _2, + "xn--trentinsd-tirol-6vb": _2, + "trentinsüd-tirol": _2, + "trentinsudtirol": _2, + "xn--trentinsdtirol-nsb": _2, + "trentinsüdtirol": _2, + "trentinsued-tirol": _2, + "trentinsuedtirol": _2, + "tuscany": _2, + "umb": _2, + "umbria": _2, + "val-d-aosta": _2, + "val-daosta": _2, + "vald-aosta": _2, + "valdaosta": _2, + "valle-aosta": _2, + "valle-d-aosta": _2, + "valle-daosta": _2, + "valleaosta": _2, + "valled-aosta": _2, + "valledaosta": _2, + "vallee-aoste": _2, + "xn--valle-aoste-ebb": _2, + "vallée-aoste": _2, + "vallee-d-aoste": _2, + "xn--valle-d-aoste-ehb": _2, + "vallée-d-aoste": _2, + "valleeaoste": _2, + "xn--valleaoste-e7a": _2, + "valléeaoste": _2, + "valleedaoste": _2, + "xn--valledaoste-ebb": _2, + "valléedaoste": _2, + "vao": _2, + "vda": _2, + "ven": _2, + "veneto": _2, + "ag": _2, + "agrigento": _2, + "al": _2, + "alessandria": _2, + "alto-adige": _2, + "altoadige": _2, + "an": _2, + "ancona": _2, + "andria-barletta-trani": _2, + "andria-trani-barletta": _2, + "andriabarlettatrani": _2, + "andriatranibarletta": _2, + "ao": _2, + "aosta": _2, + "aoste": _2, + "ap": _2, + "aq": _2, + "aquila": _2, + "ar": _2, + "arezzo": _2, + "ascoli-piceno": _2, + "ascolipiceno": _2, + "asti": _2, + "at": _2, + "av": _2, + "avellino": _2, + "ba": _2, + "balsan-sudtirol": _2, + "xn--balsan-sdtirol-nsb": _2, + "balsan-südtirol": _2, + "balsan-suedtirol": _2, + "balsan": _2, + "bari": _2, + "barletta-trani-andria": _2, + "barlettatraniandria": _2, + "belluno": _2, + "benevento": _2, + "bergamo": _2, + "bg": _2, + "bi": _2, + "biella": _2, + "bl": _2, + "bn": _2, + "bo": _2, + "bologna": _2, + "bolzano-altoadige": _2, + "bolzano": _2, + "bozen-sudtirol": _2, + "xn--bozen-sdtirol-2ob": _2, + "bozen-südtirol": _2, + "bozen-suedtirol": _2, + "bozen": _2, + "br": _2, + "brescia": _2, + "brindisi": _2, + "bs": _2, + "bt": _2, + "bulsan-sudtirol": _2, + "xn--bulsan-sdtirol-nsb": _2, + "bulsan-südtirol": _2, + "bulsan-suedtirol": _2, + "bulsan": _2, + "bz": _2, + "ca": _2, + "cagliari": _2, + "caltanissetta": _2, + "campidano-medio": _2, + "campidanomedio": _2, + "campobasso": _2, + "carbonia-iglesias": _2, + "carboniaiglesias": _2, + "carrara-massa": _2, + "carraramassa": _2, + "caserta": _2, + "catania": _2, + "catanzaro": _2, + "cb": _2, + "ce": _2, + "cesena-forli": _2, + "xn--cesena-forl-mcb": _2, + "cesena-forlì": _2, + "cesenaforli": _2, + "xn--cesenaforl-i8a": _2, + "cesenaforlì": _2, + "ch": _2, + "chieti": _2, + "ci": _2, + "cl": _2, + "cn": _2, + "co": _2, + "como": _2, + "cosenza": _2, + "cr": _2, + "cremona": _2, + "crotone": _2, + "cs": _2, + "ct": _2, + "cuneo": _2, + "cz": _2, + "dell-ogliastra": _2, + "dellogliastra": _2, + "en": _2, + "enna": _2, + "fc": _2, + "fe": _2, + "fermo": _2, + "ferrara": _2, + "fg": _2, + "fi": _2, + "firenze": _2, + "florence": _2, + "fm": _2, + "foggia": _2, + "forli-cesena": _2, + "xn--forl-cesena-fcb": _2, + "forlì-cesena": _2, + "forlicesena": _2, + "xn--forlcesena-c8a": _2, + "forlìcesena": _2, + "fr": _2, + "frosinone": _2, + "ge": _2, + "genoa": _2, + "genova": _2, + "go": _2, + "gorizia": _2, + "gr": _2, + "grosseto": _2, + "iglesias-carbonia": _2, + "iglesiascarbonia": _2, + "im": _2, + "imperia": _2, + "is": _2, + "isernia": _2, + "kr": _2, + "la-spezia": _2, + "laquila": _2, + "laspezia": _2, + "latina": _2, + "lc": _2, + "le": _2, + "lecce": _2, + "lecco": _2, + "li": _2, + "livorno": _2, + "lo": _2, + "lodi": _2, + "lt": _2, + "lu": _2, + "lucca": _2, + "macerata": _2, + "mantova": _2, + "massa-carrara": _2, + "massacarrara": _2, + "matera": _2, + "mb": _2, + "mc": _2, + "me": _2, + "medio-campidano": _2, + "mediocampidano": _2, + "messina": _2, + "mi": _2, + "milan": _2, + "milano": _2, + "mn": _2, + "mo": _2, + "modena": _2, + "monza-brianza": _2, + "monza-e-della-brianza": _2, + "monza": _2, + "monzabrianza": _2, + "monzaebrianza": _2, + "monzaedellabrianza": _2, + "ms": _2, + "mt": _2, + "na": _2, + "naples": _2, + "napoli": _2, + "no": _2, + "novara": _2, + "nu": _2, + "nuoro": _2, + "og": _2, + "ogliastra": _2, + "olbia-tempio": _2, + "olbiatempio": _2, + "or": _2, + "oristano": _2, + "ot": _2, + "pa": _2, + "padova": _2, + "padua": _2, + "palermo": _2, + "parma": _2, + "pavia": _2, + "pc": _2, + "pd": _2, + "pe": _2, + "perugia": _2, + "pesaro-urbino": _2, + "pesarourbino": _2, + "pescara": _2, + "pg": _2, + "pi": _2, + "piacenza": _2, + "pisa": _2, + "pistoia": _2, + "pn": _2, + "po": _2, + "pordenone": _2, + "potenza": _2, + "pr": _2, + "prato": _2, + "pt": _2, + "pu": _2, + "pv": _2, + "pz": _2, + "ra": _2, + "ragusa": _2, + "ravenna": _2, + "rc": _2, + "re": _2, + "reggio-calabria": _2, + "reggio-emilia": _2, + "reggiocalabria": _2, + "reggioemilia": _2, + "rg": _2, + "ri": _2, + "rieti": _2, + "rimini": _2, + "rm": _2, + "rn": _2, + "ro": _2, + "roma": _2, + "rome": _2, + "rovigo": _2, + "sa": _2, + "salerno": _2, + "sassari": _2, + "savona": _2, + "si": _2, + "siena": _2, + "siracusa": _2, + "so": _2, + "sondrio": _2, + "sp": _2, + "sr": _2, + "ss": _2, + "suedtirol": _2, + "xn--sdtirol-n2a": _2, + "südtirol": _2, + "sv": _2, + "ta": _2, + "taranto": _2, + "te": _2, + "tempio-olbia": _2, + "tempioolbia": _2, + "teramo": _2, + "terni": _2, + "tn": _2, + "to": _2, + "torino": _2, + "tp": _2, + "tr": _2, + "trani-andria-barletta": _2, + "trani-barletta-andria": _2, + "traniandriabarletta": _2, + "tranibarlettaandria": _2, + "trapani": _2, + "trento": _2, + "treviso": _2, + "trieste": _2, + "ts": _2, + "turin": _2, + "tv": _2, + "ud": _2, + "udine": _2, + "urbino-pesaro": _2, + "urbinopesaro": _2, + "va": _2, + "varese": _2, + "vb": _2, + "vc": _2, + "ve": _2, + "venezia": _2, + "venice": _2, + "verbania": _2, + "vercelli": _2, + "verona": _2, + "vi": _2, + "vibo-valentia": _2, + "vibovalentia": _2, + "vicenza": _2, + "viterbo": _2, + "vr": _2, + "vs": _2, + "vt": _2, + "vv": _2, + "12chars": _3, + "blogspot": _3, + "ibxos": _3, + "iliadboxos": _3, + "neen": [0, { + "jc": _3 + }], + "tim": [0, { + "open": [0, { + "jelastic": _14 + }] + }], + "16-b": _3, + "32-b": _3, + "64-b": _3, + "123homepage": _3, + "myspreadshop": _3, + "syncloud": _3 + }], + "je": [1, { + "co": _2, + "net": _2, + "org": _2, + "of": _3 + }], + "jm": _13, + "jo": [1, { + "com": _2, + "org": _2, + "net": _2, + "edu": _2, + "sch": _2, + "gov": _2, + "mil": _2, + "name": _2 + }], + "jobs": _2, + "jp": [1, { + "ac": _2, + "ad": _2, + "co": _2, + "ed": _2, + "go": _2, + "gr": _2, + "lg": _2, + "ne": [1, { + "aseinet": _43, + "gehirn": _3, + "ivory": _3, + "mail-box": _3, + "mints": _3, + "mokuren": _3, + "opal": _3, + "sakura": _3, + "sumomo": _3, + "topaz": _3 + }], + "or": _2, + "aichi": [1, { + "aisai": _2, + "ama": _2, + "anjo": _2, + "asuke": _2, + "chiryu": _2, + "chita": _2, + "fuso": _2, + "gamagori": _2, + "handa": _2, + "hazu": _2, + "hekinan": _2, + "higashiura": _2, + "ichinomiya": _2, + "inazawa": _2, + "inuyama": _2, + "isshiki": _2, + "iwakura": _2, + "kanie": _2, + "kariya": _2, + "kasugai": _2, + "kira": _2, + "kiyosu": _2, + "komaki": _2, + "konan": _2, + "kota": _2, + "mihama": _2, + "miyoshi": _2, + "nishio": _2, + "nisshin": _2, + "obu": _2, + "oguchi": _2, + "oharu": _2, + "okazaki": _2, + "owariasahi": _2, + "seto": _2, + "shikatsu": _2, + "shinshiro": _2, + "shitara": _2, + "tahara": _2, + "takahama": _2, + "tobishima": _2, + "toei": _2, + "togo": _2, + "tokai": _2, + "tokoname": _2, + "toyoake": _2, + "toyohashi": _2, + "toyokawa": _2, + "toyone": _2, + "toyota": _2, + "tsushima": _2, + "yatomi": _2 + }], + "akita": [1, { + "akita": _2, + "daisen": _2, + "fujisato": _2, + "gojome": _2, + "hachirogata": _2, + "happou": _2, + "higashinaruse": _2, + "honjo": _2, + "honjyo": _2, + "ikawa": _2, + "kamikoani": _2, + "kamioka": _2, + "katagami": _2, + "kazuno": _2, + "kitaakita": _2, + "kosaka": _2, + "kyowa": _2, + "misato": _2, + "mitane": _2, + "moriyoshi": _2, + "nikaho": _2, + "noshiro": _2, + "odate": _2, + "oga": _2, + "ogata": _2, + "semboku": _2, + "yokote": _2, + "yurihonjo": _2 + }], + "aomori": [1, { + "aomori": _2, + "gonohe": _2, + "hachinohe": _2, + "hashikami": _2, + "hiranai": _2, + "hirosaki": _2, + "itayanagi": _2, + "kuroishi": _2, + "misawa": _2, + "mutsu": _2, + "nakadomari": _2, + "noheji": _2, + "oirase": _2, + "owani": _2, + "rokunohe": _2, + "sannohe": _2, + "shichinohe": _2, + "shingo": _2, + "takko": _2, + "towada": _2, + "tsugaru": _2, + "tsuruta": _2 + }], + "chiba": [1, { + "abiko": _2, + "asahi": _2, + "chonan": _2, + "chosei": _2, + "choshi": _2, + "chuo": _2, + "funabashi": _2, + "futtsu": _2, + "hanamigawa": _2, + "ichihara": _2, + "ichikawa": _2, + "ichinomiya": _2, + "inzai": _2, + "isumi": _2, + "kamagaya": _2, + "kamogawa": _2, + "kashiwa": _2, + "katori": _2, + "katsuura": _2, + "kimitsu": _2, + "kisarazu": _2, + "kozaki": _2, + "kujukuri": _2, + "kyonan": _2, + "matsudo": _2, + "midori": _2, + "mihama": _2, + "minamiboso": _2, + "mobara": _2, + "mutsuzawa": _2, + "nagara": _2, + "nagareyama": _2, + "narashino": _2, + "narita": _2, + "noda": _2, + "oamishirasato": _2, + "omigawa": _2, + "onjuku": _2, + "otaki": _2, + "sakae": _2, + "sakura": _2, + "shimofusa": _2, + "shirako": _2, + "shiroi": _2, + "shisui": _2, + "sodegaura": _2, + "sosa": _2, + "tako": _2, + "tateyama": _2, + "togane": _2, + "tohnosho": _2, + "tomisato": _2, + "urayasu": _2, + "yachimata": _2, + "yachiyo": _2, + "yokaichiba": _2, + "yokoshibahikari": _2, + "yotsukaido": _2 + }], + "ehime": [1, { + "ainan": _2, + "honai": _2, + "ikata": _2, + "imabari": _2, + "iyo": _2, + "kamijima": _2, + "kihoku": _2, + "kumakogen": _2, + "masaki": _2, + "matsuno": _2, + "matsuyama": _2, + "namikata": _2, + "niihama": _2, + "ozu": _2, + "saijo": _2, + "seiyo": _2, + "shikokuchuo": _2, + "tobe": _2, + "toon": _2, + "uchiko": _2, + "uwajima": _2, + "yawatahama": _2 + }], + "fukui": [1, { + "echizen": _2, + "eiheiji": _2, + "fukui": _2, + "ikeda": _2, + "katsuyama": _2, + "mihama": _2, + "minamiechizen": _2, + "obama": _2, + "ohi": _2, + "ono": _2, + "sabae": _2, + "sakai": _2, + "takahama": _2, + "tsuruga": _2, + "wakasa": _2 + }], + "fukuoka": [1, { + "ashiya": _2, + "buzen": _2, + "chikugo": _2, + "chikuho": _2, + "chikujo": _2, + "chikushino": _2, + "chikuzen": _2, + "chuo": _2, + "dazaifu": _2, + "fukuchi": _2, + "hakata": _2, + "higashi": _2, + "hirokawa": _2, + "hisayama": _2, + "iizuka": _2, + "inatsuki": _2, + "kaho": _2, + "kasuga": _2, + "kasuya": _2, + "kawara": _2, + "keisen": _2, + "koga": _2, + "kurate": _2, + "kurogi": _2, + "kurume": _2, + "minami": _2, + "miyako": _2, + "miyama": _2, + "miyawaka": _2, + "mizumaki": _2, + "munakata": _2, + "nakagawa": _2, + "nakama": _2, + "nishi": _2, + "nogata": _2, + "ogori": _2, + "okagaki": _2, + "okawa": _2, + "oki": _2, + "omuta": _2, + "onga": _2, + "onojo": _2, + "oto": _2, + "saigawa": _2, + "sasaguri": _2, + "shingu": _2, + "shinyoshitomi": _2, + "shonai": _2, + "soeda": _2, + "sue": _2, + "tachiarai": _2, + "tagawa": _2, + "takata": _2, + "toho": _2, + "toyotsu": _2, + "tsuiki": _2, + "ukiha": _2, + "umi": _2, + "usui": _2, + "yamada": _2, + "yame": _2, + "yanagawa": _2, + "yukuhashi": _2 + }], + "fukushima": [1, { + "aizubange": _2, + "aizumisato": _2, + "aizuwakamatsu": _2, + "asakawa": _2, + "bandai": _2, + "date": _2, + "fukushima": _2, + "furudono": _2, + "futaba": _2, + "hanawa": _2, + "higashi": _2, + "hirata": _2, + "hirono": _2, + "iitate": _2, + "inawashiro": _2, + "ishikawa": _2, + "iwaki": _2, + "izumizaki": _2, + "kagamiishi": _2, + "kaneyama": _2, + "kawamata": _2, + "kitakata": _2, + "kitashiobara": _2, + "koori": _2, + "koriyama": _2, + "kunimi": _2, + "miharu": _2, + "mishima": _2, + "namie": _2, + "nango": _2, + "nishiaizu": _2, + "nishigo": _2, + "okuma": _2, + "omotego": _2, + "ono": _2, + "otama": _2, + "samegawa": _2, + "shimogo": _2, + "shirakawa": _2, + "showa": _2, + "soma": _2, + "sukagawa": _2, + "taishin": _2, + "tamakawa": _2, + "tanagura": _2, + "tenei": _2, + "yabuki": _2, + "yamato": _2, + "yamatsuri": _2, + "yanaizu": _2, + "yugawa": _2 + }], + "gifu": [1, { + "anpachi": _2, + "ena": _2, + "gifu": _2, + "ginan": _2, + "godo": _2, + "gujo": _2, + "hashima": _2, + "hichiso": _2, + "hida": _2, + "higashishirakawa": _2, + "ibigawa": _2, + "ikeda": _2, + "kakamigahara": _2, + "kani": _2, + "kasahara": _2, + "kasamatsu": _2, + "kawaue": _2, + "kitagata": _2, + "mino": _2, + "minokamo": _2, + "mitake": _2, + "mizunami": _2, + "motosu": _2, + "nakatsugawa": _2, + "ogaki": _2, + "sakahogi": _2, + "seki": _2, + "sekigahara": _2, + "shirakawa": _2, + "tajimi": _2, + "takayama": _2, + "tarui": _2, + "toki": _2, + "tomika": _2, + "wanouchi": _2, + "yamagata": _2, + "yaotsu": _2, + "yoro": _2 + }], + "gunma": [1, { + "annaka": _2, + "chiyoda": _2, + "fujioka": _2, + "higashiagatsuma": _2, + "isesaki": _2, + "itakura": _2, + "kanna": _2, + "kanra": _2, + "katashina": _2, + "kawaba": _2, + "kiryu": _2, + "kusatsu": _2, + "maebashi": _2, + "meiwa": _2, + "midori": _2, + "minakami": _2, + "naganohara": _2, + "nakanojo": _2, + "nanmoku": _2, + "numata": _2, + "oizumi": _2, + "ora": _2, + "ota": _2, + "shibukawa": _2, + "shimonita": _2, + "shinto": _2, + "showa": _2, + "takasaki": _2, + "takayama": _2, + "tamamura": _2, + "tatebayashi": _2, + "tomioka": _2, + "tsukiyono": _2, + "tsumagoi": _2, + "ueno": _2, + "yoshioka": _2 + }], + "hiroshima": [1, { + "asaminami": _2, + "daiwa": _2, + "etajima": _2, + "fuchu": _2, + "fukuyama": _2, + "hatsukaichi": _2, + "higashihiroshima": _2, + "hongo": _2, + "jinsekikogen": _2, + "kaita": _2, + "kui": _2, + "kumano": _2, + "kure": _2, + "mihara": _2, + "miyoshi": _2, + "naka": _2, + "onomichi": _2, + "osakikamijima": _2, + "otake": _2, + "saka": _2, + "sera": _2, + "seranishi": _2, + "shinichi": _2, + "shobara": _2, + "takehara": _2 + }], + "hokkaido": [1, { + "abashiri": _2, + "abira": _2, + "aibetsu": _2, + "akabira": _2, + "akkeshi": _2, + "asahikawa": _2, + "ashibetsu": _2, + "ashoro": _2, + "assabu": _2, + "atsuma": _2, + "bibai": _2, + "biei": _2, + "bifuka": _2, + "bihoro": _2, + "biratori": _2, + "chippubetsu": _2, + "chitose": _2, + "date": _2, + "ebetsu": _2, + "embetsu": _2, + "eniwa": _2, + "erimo": _2, + "esan": _2, + "esashi": _2, + "fukagawa": _2, + "fukushima": _2, + "furano": _2, + "furubira": _2, + "haboro": _2, + "hakodate": _2, + "hamatonbetsu": _2, + "hidaka": _2, + "higashikagura": _2, + "higashikawa": _2, + "hiroo": _2, + "hokuryu": _2, + "hokuto": _2, + "honbetsu": _2, + "horokanai": _2, + "horonobe": _2, + "ikeda": _2, + "imakane": _2, + "ishikari": _2, + "iwamizawa": _2, + "iwanai": _2, + "kamifurano": _2, + "kamikawa": _2, + "kamishihoro": _2, + "kamisunagawa": _2, + "kamoenai": _2, + "kayabe": _2, + "kembuchi": _2, + "kikonai": _2, + "kimobetsu": _2, + "kitahiroshima": _2, + "kitami": _2, + "kiyosato": _2, + "koshimizu": _2, + "kunneppu": _2, + "kuriyama": _2, + "kuromatsunai": _2, + "kushiro": _2, + "kutchan": _2, + "kyowa": _2, + "mashike": _2, + "matsumae": _2, + "mikasa": _2, + "minamifurano": _2, + "mombetsu": _2, + "moseushi": _2, + "mukawa": _2, + "muroran": _2, + "naie": _2, + "nakagawa": _2, + "nakasatsunai": _2, + "nakatombetsu": _2, + "nanae": _2, + "nanporo": _2, + "nayoro": _2, + "nemuro": _2, + "niikappu": _2, + "niki": _2, + "nishiokoppe": _2, + "noboribetsu": _2, + "numata": _2, + "obihiro": _2, + "obira": _2, + "oketo": _2, + "okoppe": _2, + "otaru": _2, + "otobe": _2, + "otofuke": _2, + "otoineppu": _2, + "oumu": _2, + "ozora": _2, + "pippu": _2, + "rankoshi": _2, + "rebun": _2, + "rikubetsu": _2, + "rishiri": _2, + "rishirifuji": _2, + "saroma": _2, + "sarufutsu": _2, + "shakotan": _2, + "shari": _2, + "shibecha": _2, + "shibetsu": _2, + "shikabe": _2, + "shikaoi": _2, + "shimamaki": _2, + "shimizu": _2, + "shimokawa": _2, + "shinshinotsu": _2, + "shintoku": _2, + "shiranuka": _2, + "shiraoi": _2, + "shiriuchi": _2, + "sobetsu": _2, + "sunagawa": _2, + "taiki": _2, + "takasu": _2, + "takikawa": _2, + "takinoue": _2, + "teshikaga": _2, + "tobetsu": _2, + "tohma": _2, + "tomakomai": _2, + "tomari": _2, + "toya": _2, + "toyako": _2, + "toyotomi": _2, + "toyoura": _2, + "tsubetsu": _2, + "tsukigata": _2, + "urakawa": _2, + "urausu": _2, + "uryu": _2, + "utashinai": _2, + "wakkanai": _2, + "wassamu": _2, + "yakumo": _2, + "yoichi": _2 + }], + "hyogo": [1, { + "aioi": _2, + "akashi": _2, + "ako": _2, + "amagasaki": _2, + "aogaki": _2, + "asago": _2, + "ashiya": _2, + "awaji": _2, + "fukusaki": _2, + "goshiki": _2, + "harima": _2, + "himeji": _2, + "ichikawa": _2, + "inagawa": _2, + "itami": _2, + "kakogawa": _2, + "kamigori": _2, + "kamikawa": _2, + "kasai": _2, + "kasuga": _2, + "kawanishi": _2, + "miki": _2, + "minamiawaji": _2, + "nishinomiya": _2, + "nishiwaki": _2, + "ono": _2, + "sanda": _2, + "sannan": _2, + "sasayama": _2, + "sayo": _2, + "shingu": _2, + "shinonsen": _2, + "shiso": _2, + "sumoto": _2, + "taishi": _2, + "taka": _2, + "takarazuka": _2, + "takasago": _2, + "takino": _2, + "tamba": _2, + "tatsuno": _2, + "toyooka": _2, + "yabu": _2, + "yashiro": _2, + "yoka": _2, + "yokawa": _2 + }], + "ibaraki": [1, { + "ami": _2, + "asahi": _2, + "bando": _2, + "chikusei": _2, + "daigo": _2, + "fujishiro": _2, + "hitachi": _2, + "hitachinaka": _2, + "hitachiomiya": _2, + "hitachiota": _2, + "ibaraki": _2, + "ina": _2, + "inashiki": _2, + "itako": _2, + "iwama": _2, + "joso": _2, + "kamisu": _2, + "kasama": _2, + "kashima": _2, + "kasumigaura": _2, + "koga": _2, + "miho": _2, + "mito": _2, + "moriya": _2, + "naka": _2, + "namegata": _2, + "oarai": _2, + "ogawa": _2, + "omitama": _2, + "ryugasaki": _2, + "sakai": _2, + "sakuragawa": _2, + "shimodate": _2, + "shimotsuma": _2, + "shirosato": _2, + "sowa": _2, + "suifu": _2, + "takahagi": _2, + "tamatsukuri": _2, + "tokai": _2, + "tomobe": _2, + "tone": _2, + "toride": _2, + "tsuchiura": _2, + "tsukuba": _2, + "uchihara": _2, + "ushiku": _2, + "yachiyo": _2, + "yamagata": _2, + "yawara": _2, + "yuki": _2 + }], + "ishikawa": [1, { + "anamizu": _2, + "hakui": _2, + "hakusan": _2, + "kaga": _2, + "kahoku": _2, + "kanazawa": _2, + "kawakita": _2, + "komatsu": _2, + "nakanoto": _2, + "nanao": _2, + "nomi": _2, + "nonoichi": _2, + "noto": _2, + "shika": _2, + "suzu": _2, + "tsubata": _2, + "tsurugi": _2, + "uchinada": _2, + "wajima": _2 + }], + "iwate": [1, { + "fudai": _2, + "fujisawa": _2, + "hanamaki": _2, + "hiraizumi": _2, + "hirono": _2, + "ichinohe": _2, + "ichinoseki": _2, + "iwaizumi": _2, + "iwate": _2, + "joboji": _2, + "kamaishi": _2, + "kanegasaki": _2, + "karumai": _2, + "kawai": _2, + "kitakami": _2, + "kuji": _2, + "kunohe": _2, + "kuzumaki": _2, + "miyako": _2, + "mizusawa": _2, + "morioka": _2, + "ninohe": _2, + "noda": _2, + "ofunato": _2, + "oshu": _2, + "otsuchi": _2, + "rikuzentakata": _2, + "shiwa": _2, + "shizukuishi": _2, + "sumita": _2, + "tanohata": _2, + "tono": _2, + "yahaba": _2, + "yamada": _2 + }], + "kagawa": [1, { + "ayagawa": _2, + "higashikagawa": _2, + "kanonji": _2, + "kotohira": _2, + "manno": _2, + "marugame": _2, + "mitoyo": _2, + "naoshima": _2, + "sanuki": _2, + "tadotsu": _2, + "takamatsu": _2, + "tonosho": _2, + "uchinomi": _2, + "utazu": _2, + "zentsuji": _2 + }], + "kagoshima": [1, { + "akune": _2, + "amami": _2, + "hioki": _2, + "isa": _2, + "isen": _2, + "izumi": _2, + "kagoshima": _2, + "kanoya": _2, + "kawanabe": _2, + "kinko": _2, + "kouyama": _2, + "makurazaki": _2, + "matsumoto": _2, + "minamitane": _2, + "nakatane": _2, + "nishinoomote": _2, + "satsumasendai": _2, + "soo": _2, + "tarumizu": _2, + "yusui": _2 + }], + "kanagawa": [1, { + "aikawa": _2, + "atsugi": _2, + "ayase": _2, + "chigasaki": _2, + "ebina": _2, + "fujisawa": _2, + "hadano": _2, + "hakone": _2, + "hiratsuka": _2, + "isehara": _2, + "kaisei": _2, + "kamakura": _2, + "kiyokawa": _2, + "matsuda": _2, + "minamiashigara": _2, + "miura": _2, + "nakai": _2, + "ninomiya": _2, + "odawara": _2, + "oi": _2, + "oiso": _2, + "sagamihara": _2, + "samukawa": _2, + "tsukui": _2, + "yamakita": _2, + "yamato": _2, + "yokosuka": _2, + "yugawara": _2, + "zama": _2, + "zushi": _2 + }], + "kochi": [1, { + "aki": _2, + "geisei": _2, + "hidaka": _2, + "higashitsuno": _2, + "ino": _2, + "kagami": _2, + "kami": _2, + "kitagawa": _2, + "kochi": _2, + "mihara": _2, + "motoyama": _2, + "muroto": _2, + "nahari": _2, + "nakamura": _2, + "nankoku": _2, + "nishitosa": _2, + "niyodogawa": _2, + "ochi": _2, + "okawa": _2, + "otoyo": _2, + "otsuki": _2, + "sakawa": _2, + "sukumo": _2, + "susaki": _2, + "tosa": _2, + "tosashimizu": _2, + "toyo": _2, + "tsuno": _2, + "umaji": _2, + "yasuda": _2, + "yusuhara": _2 + }], + "kumamoto": [1, { + "amakusa": _2, + "arao": _2, + "aso": _2, + "choyo": _2, + "gyokuto": _2, + "kamiamakusa": _2, + "kikuchi": _2, + "kumamoto": _2, + "mashiki": _2, + "mifune": _2, + "minamata": _2, + "minamioguni": _2, + "nagasu": _2, + "nishihara": _2, + "oguni": _2, + "ozu": _2, + "sumoto": _2, + "takamori": _2, + "uki": _2, + "uto": _2, + "yamaga": _2, + "yamato": _2, + "yatsushiro": _2 + }], + "kyoto": [1, { + "ayabe": _2, + "fukuchiyama": _2, + "higashiyama": _2, + "ide": _2, + "ine": _2, + "joyo": _2, + "kameoka": _2, + "kamo": _2, + "kita": _2, + "kizu": _2, + "kumiyama": _2, + "kyotamba": _2, + "kyotanabe": _2, + "kyotango": _2, + "maizuru": _2, + "minami": _2, + "minamiyamashiro": _2, + "miyazu": _2, + "muko": _2, + "nagaokakyo": _2, + "nakagyo": _2, + "nantan": _2, + "oyamazaki": _2, + "sakyo": _2, + "seika": _2, + "tanabe": _2, + "uji": _2, + "ujitawara": _2, + "wazuka": _2, + "yamashina": _2, + "yawata": _2 + }], + "mie": [1, { + "asahi": _2, + "inabe": _2, + "ise": _2, + "kameyama": _2, + "kawagoe": _2, + "kiho": _2, + "kisosaki": _2, + "kiwa": _2, + "komono": _2, + "kumano": _2, + "kuwana": _2, + "matsusaka": _2, + "meiwa": _2, + "mihama": _2, + "minamiise": _2, + "misugi": _2, + "miyama": _2, + "nabari": _2, + "shima": _2, + "suzuka": _2, + "tado": _2, + "taiki": _2, + "taki": _2, + "tamaki": _2, + "toba": _2, + "tsu": _2, + "udono": _2, + "ureshino": _2, + "watarai": _2, + "yokkaichi": _2 + }], + "miyagi": [1, { + "furukawa": _2, + "higashimatsushima": _2, + "ishinomaki": _2, + "iwanuma": _2, + "kakuda": _2, + "kami": _2, + "kawasaki": _2, + "marumori": _2, + "matsushima": _2, + "minamisanriku": _2, + "misato": _2, + "murata": _2, + "natori": _2, + "ogawara": _2, + "ohira": _2, + "onagawa": _2, + "osaki": _2, + "rifu": _2, + "semine": _2, + "shibata": _2, + "shichikashuku": _2, + "shikama": _2, + "shiogama": _2, + "shiroishi": _2, + "tagajo": _2, + "taiwa": _2, + "tome": _2, + "tomiya": _2, + "wakuya": _2, + "watari": _2, + "yamamoto": _2, + "zao": _2 + }], + "miyazaki": [1, { + "aya": _2, + "ebino": _2, + "gokase": _2, + "hyuga": _2, + "kadogawa": _2, + "kawaminami": _2, + "kijo": _2, + "kitagawa": _2, + "kitakata": _2, + "kitaura": _2, + "kobayashi": _2, + "kunitomi": _2, + "kushima": _2, + "mimata": _2, + "miyakonojo": _2, + "miyazaki": _2, + "morotsuka": _2, + "nichinan": _2, + "nishimera": _2, + "nobeoka": _2, + "saito": _2, + "shiiba": _2, + "shintomi": _2, + "takaharu": _2, + "takanabe": _2, + "takazaki": _2, + "tsuno": _2 + }], + "nagano": [1, { + "achi": _2, + "agematsu": _2, + "anan": _2, + "aoki": _2, + "asahi": _2, + "azumino": _2, + "chikuhoku": _2, + "chikuma": _2, + "chino": _2, + "fujimi": _2, + "hakuba": _2, + "hara": _2, + "hiraya": _2, + "iida": _2, + "iijima": _2, + "iiyama": _2, + "iizuna": _2, + "ikeda": _2, + "ikusaka": _2, + "ina": _2, + "karuizawa": _2, + "kawakami": _2, + "kiso": _2, + "kisofukushima": _2, + "kitaaiki": _2, + "komagane": _2, + "komoro": _2, + "matsukawa": _2, + "matsumoto": _2, + "miasa": _2, + "minamiaiki": _2, + "minamimaki": _2, + "minamiminowa": _2, + "minowa": _2, + "miyada": _2, + "miyota": _2, + "mochizuki": _2, + "nagano": _2, + "nagawa": _2, + "nagiso": _2, + "nakagawa": _2, + "nakano": _2, + "nozawaonsen": _2, + "obuse": _2, + "ogawa": _2, + "okaya": _2, + "omachi": _2, + "omi": _2, + "ookuwa": _2, + "ooshika": _2, + "otaki": _2, + "otari": _2, + "sakae": _2, + "sakaki": _2, + "saku": _2, + "sakuho": _2, + "shimosuwa": _2, + "shinanomachi": _2, + "shiojiri": _2, + "suwa": _2, + "suzaka": _2, + "takagi": _2, + "takamori": _2, + "takayama": _2, + "tateshina": _2, + "tatsuno": _2, + "togakushi": _2, + "togura": _2, + "tomi": _2, + "ueda": _2, + "wada": _2, + "yamagata": _2, + "yamanouchi": _2, + "yasaka": _2, + "yasuoka": _2 + }], + "nagasaki": [1, { + "chijiwa": _2, + "futsu": _2, + "goto": _2, + "hasami": _2, + "hirado": _2, + "iki": _2, + "isahaya": _2, + "kawatana": _2, + "kuchinotsu": _2, + "matsuura": _2, + "nagasaki": _2, + "obama": _2, + "omura": _2, + "oseto": _2, + "saikai": _2, + "sasebo": _2, + "seihi": _2, + "shimabara": _2, + "shinkamigoto": _2, + "togitsu": _2, + "tsushima": _2, + "unzen": _2 + }], + "nara": [1, { + "ando": _2, + "gose": _2, + "heguri": _2, + "higashiyoshino": _2, + "ikaruga": _2, + "ikoma": _2, + "kamikitayama": _2, + "kanmaki": _2, + "kashiba": _2, + "kashihara": _2, + "katsuragi": _2, + "kawai": _2, + "kawakami": _2, + "kawanishi": _2, + "koryo": _2, + "kurotaki": _2, + "mitsue": _2, + "miyake": _2, + "nara": _2, + "nosegawa": _2, + "oji": _2, + "ouda": _2, + "oyodo": _2, + "sakurai": _2, + "sango": _2, + "shimoichi": _2, + "shimokitayama": _2, + "shinjo": _2, + "soni": _2, + "takatori": _2, + "tawaramoto": _2, + "tenkawa": _2, + "tenri": _2, + "uda": _2, + "yamatokoriyama": _2, + "yamatotakada": _2, + "yamazoe": _2, + "yoshino": _2 + }], + "niigata": [1, { + "aga": _2, + "agano": _2, + "gosen": _2, + "itoigawa": _2, + "izumozaki": _2, + "joetsu": _2, + "kamo": _2, + "kariwa": _2, + "kashiwazaki": _2, + "minamiuonuma": _2, + "mitsuke": _2, + "muika": _2, + "murakami": _2, + "myoko": _2, + "nagaoka": _2, + "niigata": _2, + "ojiya": _2, + "omi": _2, + "sado": _2, + "sanjo": _2, + "seiro": _2, + "seirou": _2, + "sekikawa": _2, + "shibata": _2, + "tagami": _2, + "tainai": _2, + "tochio": _2, + "tokamachi": _2, + "tsubame": _2, + "tsunan": _2, + "uonuma": _2, + "yahiko": _2, + "yoita": _2, + "yuzawa": _2 + }], + "oita": [1, { + "beppu": _2, + "bungoono": _2, + "bungotakada": _2, + "hasama": _2, + "hiji": _2, + "himeshima": _2, + "hita": _2, + "kamitsue": _2, + "kokonoe": _2, + "kuju": _2, + "kunisaki": _2, + "kusu": _2, + "oita": _2, + "saiki": _2, + "taketa": _2, + "tsukumi": _2, + "usa": _2, + "usuki": _2, + "yufu": _2 + }], + "okayama": [1, { + "akaiwa": _2, + "asakuchi": _2, + "bizen": _2, + "hayashima": _2, + "ibara": _2, + "kagamino": _2, + "kasaoka": _2, + "kibichuo": _2, + "kumenan": _2, + "kurashiki": _2, + "maniwa": _2, + "misaki": _2, + "nagi": _2, + "niimi": _2, + "nishiawakura": _2, + "okayama": _2, + "satosho": _2, + "setouchi": _2, + "shinjo": _2, + "shoo": _2, + "soja": _2, + "takahashi": _2, + "tamano": _2, + "tsuyama": _2, + "wake": _2, + "yakage": _2 + }], + "okinawa": [1, { + "aguni": _2, + "ginowan": _2, + "ginoza": _2, + "gushikami": _2, + "haebaru": _2, + "higashi": _2, + "hirara": _2, + "iheya": _2, + "ishigaki": _2, + "ishikawa": _2, + "itoman": _2, + "izena": _2, + "kadena": _2, + "kin": _2, + "kitadaito": _2, + "kitanakagusuku": _2, + "kumejima": _2, + "kunigami": _2, + "minamidaito": _2, + "motobu": _2, + "nago": _2, + "naha": _2, + "nakagusuku": _2, + "nakijin": _2, + "nanjo": _2, + "nishihara": _2, + "ogimi": _2, + "okinawa": _2, + "onna": _2, + "shimoji": _2, + "taketomi": _2, + "tarama": _2, + "tokashiki": _2, + "tomigusuku": _2, + "tonaki": _2, + "urasoe": _2, + "uruma": _2, + "yaese": _2, + "yomitan": _2, + "yonabaru": _2, + "yonaguni": _2, + "zamami": _2 + }], + "osaka": [1, { + "abeno": _2, + "chihayaakasaka": _2, + "chuo": _2, + "daito": _2, + "fujiidera": _2, + "habikino": _2, + "hannan": _2, + "higashiosaka": _2, + "higashisumiyoshi": _2, + "higashiyodogawa": _2, + "hirakata": _2, + "ibaraki": _2, + "ikeda": _2, + "izumi": _2, + "izumiotsu": _2, + "izumisano": _2, + "kadoma": _2, + "kaizuka": _2, + "kanan": _2, + "kashiwara": _2, + "katano": _2, + "kawachinagano": _2, + "kishiwada": _2, + "kita": _2, + "kumatori": _2, + "matsubara": _2, + "minato": _2, + "minoh": _2, + "misaki": _2, + "moriguchi": _2, + "neyagawa": _2, + "nishi": _2, + "nose": _2, + "osakasayama": _2, + "sakai": _2, + "sayama": _2, + "sennan": _2, + "settsu": _2, + "shijonawate": _2, + "shimamoto": _2, + "suita": _2, + "tadaoka": _2, + "taishi": _2, + "tajiri": _2, + "takaishi": _2, + "takatsuki": _2, + "tondabayashi": _2, + "toyonaka": _2, + "toyono": _2, + "yao": _2 + }], + "saga": [1, { + "ariake": _2, + "arita": _2, + "fukudomi": _2, + "genkai": _2, + "hamatama": _2, + "hizen": _2, + "imari": _2, + "kamimine": _2, + "kanzaki": _2, + "karatsu": _2, + "kashima": _2, + "kitagata": _2, + "kitahata": _2, + "kiyama": _2, + "kouhoku": _2, + "kyuragi": _2, + "nishiarita": _2, + "ogi": _2, + "omachi": _2, + "ouchi": _2, + "saga": _2, + "shiroishi": _2, + "taku": _2, + "tara": _2, + "tosu": _2, + "yoshinogari": _2 + }], + "saitama": [1, { + "arakawa": _2, + "asaka": _2, + "chichibu": _2, + "fujimi": _2, + "fujimino": _2, + "fukaya": _2, + "hanno": _2, + "hanyu": _2, + "hasuda": _2, + "hatogaya": _2, + "hatoyama": _2, + "hidaka": _2, + "higashichichibu": _2, + "higashimatsuyama": _2, + "honjo": _2, + "ina": _2, + "iruma": _2, + "iwatsuki": _2, + "kamiizumi": _2, + "kamikawa": _2, + "kamisato": _2, + "kasukabe": _2, + "kawagoe": _2, + "kawaguchi": _2, + "kawajima": _2, + "kazo": _2, + "kitamoto": _2, + "koshigaya": _2, + "kounosu": _2, + "kuki": _2, + "kumagaya": _2, + "matsubushi": _2, + "minano": _2, + "misato": _2, + "miyashiro": _2, + "miyoshi": _2, + "moroyama": _2, + "nagatoro": _2, + "namegawa": _2, + "niiza": _2, + "ogano": _2, + "ogawa": _2, + "ogose": _2, + "okegawa": _2, + "omiya": _2, + "otaki": _2, + "ranzan": _2, + "ryokami": _2, + "saitama": _2, + "sakado": _2, + "satte": _2, + "sayama": _2, + "shiki": _2, + "shiraoka": _2, + "soka": _2, + "sugito": _2, + "toda": _2, + "tokigawa": _2, + "tokorozawa": _2, + "tsurugashima": _2, + "urawa": _2, + "warabi": _2, + "yashio": _2, + "yokoze": _2, + "yono": _2, + "yorii": _2, + "yoshida": _2, + "yoshikawa": _2, + "yoshimi": _2 + }], + "shiga": [1, { + "aisho": _2, + "gamo": _2, + "higashiomi": _2, + "hikone": _2, + "koka": _2, + "konan": _2, + "kosei": _2, + "koto": _2, + "kusatsu": _2, + "maibara": _2, + "moriyama": _2, + "nagahama": _2, + "nishiazai": _2, + "notogawa": _2, + "omihachiman": _2, + "otsu": _2, + "ritto": _2, + "ryuoh": _2, + "takashima": _2, + "takatsuki": _2, + "torahime": _2, + "toyosato": _2, + "yasu": _2 + }], + "shimane": [1, { + "akagi": _2, + "ama": _2, + "gotsu": _2, + "hamada": _2, + "higashiizumo": _2, + "hikawa": _2, + "hikimi": _2, + "izumo": _2, + "kakinoki": _2, + "masuda": _2, + "matsue": _2, + "misato": _2, + "nishinoshima": _2, + "ohda": _2, + "okinoshima": _2, + "okuizumo": _2, + "shimane": _2, + "tamayu": _2, + "tsuwano": _2, + "unnan": _2, + "yakumo": _2, + "yasugi": _2, + "yatsuka": _2 + }], + "shizuoka": [1, { + "arai": _2, + "atami": _2, + "fuji": _2, + "fujieda": _2, + "fujikawa": _2, + "fujinomiya": _2, + "fukuroi": _2, + "gotemba": _2, + "haibara": _2, + "hamamatsu": _2, + "higashiizu": _2, + "ito": _2, + "iwata": _2, + "izu": _2, + "izunokuni": _2, + "kakegawa": _2, + "kannami": _2, + "kawanehon": _2, + "kawazu": _2, + "kikugawa": _2, + "kosai": _2, + "makinohara": _2, + "matsuzaki": _2, + "minamiizu": _2, + "mishima": _2, + "morimachi": _2, + "nishiizu": _2, + "numazu": _2, + "omaezaki": _2, + "shimada": _2, + "shimizu": _2, + "shimoda": _2, + "shizuoka": _2, + "susono": _2, + "yaizu": _2, + "yoshida": _2 + }], + "tochigi": [1, { + "ashikaga": _2, + "bato": _2, + "haga": _2, + "ichikai": _2, + "iwafune": _2, + "kaminokawa": _2, + "kanuma": _2, + "karasuyama": _2, + "kuroiso": _2, + "mashiko": _2, + "mibu": _2, + "moka": _2, + "motegi": _2, + "nasu": _2, + "nasushiobara": _2, + "nikko": _2, + "nishikata": _2, + "nogi": _2, + "ohira": _2, + "ohtawara": _2, + "oyama": _2, + "sakura": _2, + "sano": _2, + "shimotsuke": _2, + "shioya": _2, + "takanezawa": _2, + "tochigi": _2, + "tsuga": _2, + "ujiie": _2, + "utsunomiya": _2, + "yaita": _2 + }], + "tokushima": [1, { + "aizumi": _2, + "anan": _2, + "ichiba": _2, + "itano": _2, + "kainan": _2, + "komatsushima": _2, + "matsushige": _2, + "mima": _2, + "minami": _2, + "miyoshi": _2, + "mugi": _2, + "nakagawa": _2, + "naruto": _2, + "sanagochi": _2, + "shishikui": _2, + "tokushima": _2, + "wajiki": _2 + }], + "tokyo": [1, { + "adachi": _2, + "akiruno": _2, + "akishima": _2, + "aogashima": _2, + "arakawa": _2, + "bunkyo": _2, + "chiyoda": _2, + "chofu": _2, + "chuo": _2, + "edogawa": _2, + "fuchu": _2, + "fussa": _2, + "hachijo": _2, + "hachioji": _2, + "hamura": _2, + "higashikurume": _2, + "higashimurayama": _2, + "higashiyamato": _2, + "hino": _2, + "hinode": _2, + "hinohara": _2, + "inagi": _2, + "itabashi": _2, + "katsushika": _2, + "kita": _2, + "kiyose": _2, + "kodaira": _2, + "koganei": _2, + "kokubunji": _2, + "komae": _2, + "koto": _2, + "kouzushima": _2, + "kunitachi": _2, + "machida": _2, + "meguro": _2, + "minato": _2, + "mitaka": _2, + "mizuho": _2, + "musashimurayama": _2, + "musashino": _2, + "nakano": _2, + "nerima": _2, + "ogasawara": _2, + "okutama": _2, + "ome": _2, + "oshima": _2, + "ota": _2, + "setagaya": _2, + "shibuya": _2, + "shinagawa": _2, + "shinjuku": _2, + "suginami": _2, + "sumida": _2, + "tachikawa": _2, + "taito": _2, + "tama": _2, + "toshima": _2 + }], + "tottori": [1, { + "chizu": _2, + "hino": _2, + "kawahara": _2, + "koge": _2, + "kotoura": _2, + "misasa": _2, + "nanbu": _2, + "nichinan": _2, + "sakaiminato": _2, + "tottori": _2, + "wakasa": _2, + "yazu": _2, + "yonago": _2 + }], + "toyama": [1, { + "asahi": _2, + "fuchu": _2, + "fukumitsu": _2, + "funahashi": _2, + "himi": _2, + "imizu": _2, + "inami": _2, + "johana": _2, + "kamiichi": _2, + "kurobe": _2, + "nakaniikawa": _2, + "namerikawa": _2, + "nanto": _2, + "nyuzen": _2, + "oyabe": _2, + "taira": _2, + "takaoka": _2, + "tateyama": _2, + "toga": _2, + "tonami": _2, + "toyama": _2, + "unazuki": _2, + "uozu": _2, + "yamada": _2 + }], + "wakayama": [1, { + "arida": _2, + "aridagawa": _2, + "gobo": _2, + "hashimoto": _2, + "hidaka": _2, + "hirogawa": _2, + "inami": _2, + "iwade": _2, + "kainan": _2, + "kamitonda": _2, + "katsuragi": _2, + "kimino": _2, + "kinokawa": _2, + "kitayama": _2, + "koya": _2, + "koza": _2, + "kozagawa": _2, + "kudoyama": _2, + "kushimoto": _2, + "mihama": _2, + "misato": _2, + "nachikatsuura": _2, + "shingu": _2, + "shirahama": _2, + "taiji": _2, + "tanabe": _2, + "wakayama": _2, + "yuasa": _2, + "yura": _2 + }], + "yamagata": [1, { + "asahi": _2, + "funagata": _2, + "higashine": _2, + "iide": _2, + "kahoku": _2, + "kaminoyama": _2, + "kaneyama": _2, + "kawanishi": _2, + "mamurogawa": _2, + "mikawa": _2, + "murayama": _2, + "nagai": _2, + "nakayama": _2, + "nanyo": _2, + "nishikawa": _2, + "obanazawa": _2, + "oe": _2, + "oguni": _2, + "ohkura": _2, + "oishida": _2, + "sagae": _2, + "sakata": _2, + "sakegawa": _2, + "shinjo": _2, + "shirataka": _2, + "shonai": _2, + "takahata": _2, + "tendo": _2, + "tozawa": _2, + "tsuruoka": _2, + "yamagata": _2, + "yamanobe": _2, + "yonezawa": _2, + "yuza": _2 + }], + "yamaguchi": [1, { + "abu": _2, + "hagi": _2, + "hikari": _2, + "hofu": _2, + "iwakuni": _2, + "kudamatsu": _2, + "mitou": _2, + "nagato": _2, + "oshima": _2, + "shimonoseki": _2, + "shunan": _2, + "tabuse": _2, + "tokuyama": _2, + "toyota": _2, + "ube": _2, + "yuu": _2 + }], + "yamanashi": [1, { + "chuo": _2, + "doshi": _2, + "fuefuki": _2, + "fujikawa": _2, + "fujikawaguchiko": _2, + "fujiyoshida": _2, + "hayakawa": _2, + "hokuto": _2, + "ichikawamisato": _2, + "kai": _2, + "kofu": _2, + "koshu": _2, + "kosuge": _2, + "minami-alps": _2, + "minobu": _2, + "nakamichi": _2, + "nanbu": _2, + "narusawa": _2, + "nirasaki": _2, + "nishikatsura": _2, + "oshino": _2, + "otsuki": _2, + "showa": _2, + "tabayama": _2, + "tsuru": _2, + "uenohara": _2, + "yamanakako": _2, + "yamanashi": _2 + }], + "xn--4pvxs": _2, + "栃木": _2, + "xn--vgu402c": _2, + "愛知": _2, + "xn--c3s14m": _2, + "愛媛": _2, + "xn--f6qx53a": _2, + "兵庫": _2, + "xn--8pvr4u": _2, + "熊本": _2, + "xn--uist22h": _2, + "茨城": _2, + "xn--djrs72d6uy": _2, + "北海é“": _2, + "xn--mkru45i": _2, + "åƒè‘‰": _2, + "xn--0trq7p7nn": _2, + "和歌山": _2, + "xn--8ltr62k": _2, + "é•·å´Ž": _2, + "xn--2m4a15e": _2, + "長野": _2, + "xn--efvn9s": _2, + "新潟": _2, + "xn--32vp30h": _2, + "é’æ£®": _2, + "xn--4it797k": _2, + "é™å²¡": _2, + "xn--1lqs71d": _2, + "æ±äº¬": _2, + "xn--5rtp49c": _2, + "石å·": _2, + "xn--5js045d": _2, + "埼玉": _2, + "xn--ehqz56n": _2, + "三é‡": _2, + "xn--1lqs03n": _2, + "京都": _2, + "xn--qqqt11m": _2, + "ä½è³€": _2, + "xn--kbrq7o": _2, + "大分": _2, + "xn--pssu33l": _2, + "大阪": _2, + "xn--ntsq17g": _2, + "奈良": _2, + "xn--uisz3g": _2, + "宮城": _2, + "xn--6btw5a": _2, + "宮崎": _2, + "xn--1ctwo": _2, + "富山": _2, + "xn--6orx2r": _2, + "å±±å£": _2, + "xn--rht61e": _2, + "山形": _2, + "xn--rht27z": _2, + "山梨": _2, + "xn--djty4k": _2, + "岩手": _2, + "xn--nit225k": _2, + "å²é˜œ": _2, + "xn--rht3d": _2, + "岡山": _2, + "xn--klty5x": _2, + "å³¶æ ¹": _2, + "xn--kltx9a": _2, + "広島": _2, + "xn--kltp7d": _2, + "徳島": _2, + "xn--uuwu58a": _2, + "沖縄": _2, + "xn--zbx025d": _2, + "滋賀": _2, + "xn--ntso0iqx3a": _2, + "神奈å·": _2, + "xn--elqq16h": _2, + "ç¦äº•": _2, + "xn--4it168d": _2, + "ç¦å²¡": _2, + "xn--klt787d": _2, + "ç¦å³¶": _2, + "xn--rny31h": _2, + "ç§‹ç”°": _2, + "xn--7t0a264c": _2, + "群馬": _2, + "xn--5rtq34k": _2, + "香å·": _2, + "xn--k7yn95e": _2, + "高知": _2, + "xn--tor131o": _2, + "é³¥å–": _2, + "xn--d5qv7z876c": _2, + "鹿å…å³¶": _2, + "kawasaki": _13, + "kitakyushu": _13, + "kobe": _13, + "nagoya": _13, + "sapporo": _13, + "sendai": _13, + "yokohama": _13, + "buyshop": _3, + "fashionstore": _3, + "handcrafted": _3, + "kawaiishop": _3, + "supersale": _3, + "theshop": _3, + "usercontent": _3, + "angry": _3, + "babyblue": _3, + "babymilk": _3, + "backdrop": _3, + "bambina": _3, + "bitter": _3, + "blush": _3, + "boo": _3, + "boy": _3, + "boyfriend": _3, + "but": _3, + "candypop": _3, + "capoo": _3, + "catfood": _3, + "cheap": _3, + "chicappa": _3, + "chillout": _3, + "chips": _3, + "chowder": _3, + "chu": _3, + "ciao": _3, + "cocotte": _3, + "coolblog": _3, + "cranky": _3, + "cutegirl": _3, + "daa": _3, + "deca": _3, + "deci": _3, + "digick": _3, + "egoism": _3, + "fakefur": _3, + "fem": _3, + "flier": _3, + "floppy": _3, + "fool": _3, + "frenchkiss": _3, + "girlfriend": _3, + "girly": _3, + "gloomy": _3, + "gonna": _3, + "greater": _3, + "hacca": _3, + "heavy": _3, + "her": _3, + "hiho": _3, + "hippy": _3, + "holy": _3, + "hungry": _3, + "icurus": _3, + "itigo": _3, + "jellybean": _3, + "kikirara": _3, + "kill": _3, + "kilo": _3, + "kuron": _3, + "littlestar": _3, + "lolipopmc": _3, + "lolitapunk": _3, + "lomo": _3, + "lovepop": _3, + "lovesick": _3, + "main": _3, + "mods": _3, + "mond": _3, + "mongolian": _3, + "moo": _3, + "namaste": _3, + "nikita": _3, + "nobushi": _3, + "noor": _3, + "oops": _3, + "parallel": _3, + "parasite": _3, + "pecori": _3, + "peewee": _3, + "penne": _3, + "pepper": _3, + "perma": _3, + "pigboat": _3, + "pinoko": _3, + "punyu": _3, + "pupu": _3, + "pussycat": _3, + "pya": _3, + "raindrop": _3, + "readymade": _3, + "sadist": _3, + "schoolbus": _3, + "secret": _3, + "staba": _3, + "stripper": _3, + "sub": _3, + "sunnyday": _3, + "thick": _3, + "tonkotsu": _3, + "under": _3, + "upper": _3, + "velvet": _3, + "verse": _3, + "versus": _3, + "vivian": _3, + "watson": _3, + "weblike": _3, + "whitesnow": _3, + "zombie": _3, + "blogspot": _3, + "2-d": _3, + "bona": _3, + "crap": _3, + "daynight": _3, + "eek": _3, + "flop": _3, + "halfmoon": _3, + "jeez": _3, + "matrix": _3, + "mimoza": _3, + "netgamers": _3, + "nyanta": _3, + "o0o0": _3, + "rdy": _3, + "rgr": _3, + "rulez": _3, + "sakurastorage": [0, { + "isk01": _48, + "isk02": _48 + }], + "saloon": _3, + "sblo": _3, + "skr": _3, + "tank": _3, + "uh-oh": _3, + "undo": _3, + "webaccel": [0, { + "rs": _3, + "user": _3 + }], + "websozai": _3, + "xii": _3 + }], + "ke": [1, { + "ac": _2, + "co": _7, + "go": _2, + "info": _2, + "me": _2, + "mobi": _2, + "ne": _2, + "or": _2, + "sc": _2 + }], + "kg": [1, { + "org": _2, + "net": _2, + "com": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "io": _3, + "jp": _3, + "tv": _3, + "uk": _3, + "us": _3 + }], + "kh": _13, + "ki": _49, + "km": [1, { + "org": _2, + "nom": _2, + "gov": _2, + "prd": _2, + "tm": _2, + "edu": _2, + "mil": _2, + "ass": _2, + "com": _2, + "coop": _2, + "asso": _2, + "presse": _2, + "medecin": _2, + "notaires": _2, + "pharmaciens": _2, + "veterinaire": _2, + "gouv": _2 + }], + "kn": [1, { + "net": _2, + "org": _2, + "edu": _2, + "gov": _2 + }], + "kp": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "rep": _2, + "tra": _2 + }], + "kr": [1, { + "ac": _2, + "co": _2, + "es": _2, + "go": _2, + "hs": _2, + "kg": _2, + "mil": _2, + "ms": _2, + "ne": _2, + "or": _2, + "pe": _2, + "re": _2, + "sc": _2, + "busan": _2, + "chungbuk": _2, + "chungnam": _2, + "daegu": _2, + "daejeon": _2, + "gangwon": _2, + "gwangju": _2, + "gyeongbuk": _2, + "gyeonggi": _2, + "gyeongnam": _2, + "incheon": _2, + "jeju": _2, + "jeonbuk": _2, + "jeonnam": _2, + "seoul": _2, + "ulsan": _2, + "blogspot": _3 + }], + "kw": [1, { + "com": _2, + "edu": _2, + "emb": _2, + "gov": _2, + "ind": _2, + "net": _2, + "org": _2 + }], + "ky": _40, + "kz": [1, { + "org": _2, + "edu": _2, + "net": _2, + "gov": _2, + "mil": _2, + "com": _2, + "jcloud": _3, + "kazteleport": [0, { + "upaas": _3 + }] + }], + "la": [1, { + "int": _2, + "net": _2, + "info": _2, + "edu": _2, + "gov": _2, + "per": _2, + "com": _2, + "org": _2, + "bnr": _3, + "c": _3 + }], + "lb": _4, + "lc": [1, { + "com": _2, + "net": _2, + "co": _2, + "org": _2, + "edu": _2, + "gov": _2, + "oy": _3 + }], + "li": [1, { + "blogspot": _3, + "caa": _3 + }], + "lk": [1, { + "gov": _2, + "sch": _2, + "net": _2, + "int": _2, + "com": _2, + "org": _2, + "edu": _2, + "ngo": _2, + "soc": _2, + "web": _2, + "ltd": _2, + "assn": _2, + "grp": _2, + "hotel": _2, + "ac": _2 + }], + "lr": _4, + "ls": [1, { + "ac": _2, + "biz": _2, + "co": _2, + "edu": _2, + "gov": _2, + "info": _2, + "net": _2, + "org": _2, + "sc": _2, + "de": _3 + }], + "lt": _50, + "lu": [1, { + "blogspot": _3, + "123website": _3 + }], + "lv": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "org": _2, + "mil": _2, + "id": _2, + "net": _2, + "asn": _2, + "conf": _2 + }], + "ly": [1, { + "com": _2, + "net": _2, + "gov": _2, + "plc": _2, + "edu": _2, + "sch": _2, + "med": _2, + "org": _2, + "id": _2 + }], + "ma": [1, { + "co": _2, + "net": _2, + "gov": _2, + "org": _2, + "ac": _2, + "press": _2 + }], + "mc": [1, { + "tm": _2, + "asso": _2 + }], + "md": [1, { + "blogspot": _3, + "at": _3, + "de": _3, + "jp": _3, + "to": _3 + }], + "me": [1, { + "co": _2, + "net": _2, + "org": _2, + "edu": _2, + "ac": _2, + "gov": _2, + "its": _2, + "priv": _2, + "c66": _3, + "daplie": [2, { + "localhost": _3 + }], + "edgestack": _3, + "filegear": _3, + "filegear-au": _3, + "filegear-de": _3, + "filegear-gb": _3, + "filegear-ie": _3, + "filegear-jp": _3, + "filegear-sg": _3, + "glitch": _3, + "ravendb": _3, + "lohmus": _3, + "barsy": _3, + "mcpe": _3, + "mcdir": _3, + "soundcast": _3, + "tcp4": _3, + "brasilia": _3, + "ddns": _3, + "dnsfor": _3, + "hopto": _3, + "loginto": _3, + "noip": _3, + "webhop": _3, + "vp4": _3, + "diskstation": _3, + "dscloud": _3, + "i234": _3, + "myds": _3, + "synology": _3, + "transip": _38, + "wedeploy": _3, + "yombo": _3, + "nohost": _3 + }], + "mg": [1, { + "org": _2, + "nom": _2, + "gov": _2, + "prd": _2, + "tm": _2, + "edu": _2, + "mil": _2, + "com": _2, + "co": _2 + }], + "mh": _2, + "mil": _2, + "mk": [1, { + "com": _2, + "org": _2, + "net": _2, + "edu": _2, + "gov": _2, + "inf": _2, + "name": _2, + "blogspot": _3 + }], + "ml": [1, { + "com": _2, + "edu": _2, + "gouv": _2, + "gov": _2, + "net": _2, + "org": _2, + "presse": _2 + }], + "mm": _13, + "mn": [1, { + "gov": _2, + "edu": _2, + "org": _2, + "nyc": _3 + }], + "mo": _4, + "mobi": [1, { + "barsy": _3, + "dscloud": _3 + }], + "mp": [1, { + "ju": _3 + }], + "mq": _2, + "mr": _50, + "ms": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "net": _2, + "org": _2, + "lab": _3, + "minisite": _3 + }], + "mt": [1, { + "com": _7, + "edu": _2, + "net": _2, + "org": _2 + }], + "mu": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "ac": _2, + "co": _2, + "or": _2 + }], + "museum": _2, + "mv": [1, { + "aero": _2, + "biz": _2, + "com": _2, + "coop": _2, + "edu": _2, + "gov": _2, + "info": _2, + "int": _2, + "mil": _2, + "museum": _2, + "name": _2, + "net": _2, + "org": _2, + "pro": _2 + }], + "mw": [1, { + "ac": _2, + "biz": _2, + "co": _2, + "com": _2, + "coop": _2, + "edu": _2, + "gov": _2, + "int": _2, + "museum": _2, + "net": _2, + "org": _2 + }], + "mx": [1, { + "com": _2, + "org": _2, + "gob": _2, + "edu": _2, + "net": _2, + "blogspot": _3 + }], + "my": [1, { + "biz": _2, + "com": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "name": _2, + "net": _2, + "org": _2, + "blogspot": _3 + }], + "mz": [1, { + "ac": _2, + "adv": _2, + "co": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "net": _2, + "org": _2 + }], + "na": [1, { + "info": _2, + "pro": _2, + "name": _2, + "school": _2, + "or": _2, + "dr": _2, + "us": _2, + "mx": _2, + "ca": _2, + "in": _2, + "cc": _2, + "tv": _2, + "ws": _2, + "mobi": _2, + "co": _2, + "com": _2, + "org": _2 + }], + "name": [1, { + "her": _53, + "his": _53 + }], + "nc": [1, { + "asso": _2, + "nom": _2 + }], + "ne": _2, + "net": [1, { + "adobeaemcloud": _3, + "adobeio-static": _3, + "adobeioruntime": _3, + "akadns": _3, + "akamai": _3, + "akamai-staging": _3, + "akamaiedge": _3, + "akamaiedge-staging": _3, + "akamaihd": _3, + "akamaihd-staging": _3, + "akamaiorigin": _3, + "akamaiorigin-staging": _3, + "akamaized": _3, + "akamaized-staging": _3, + "edgekey": _3, + "edgekey-staging": _3, + "edgesuite": _3, + "edgesuite-staging": _3, + "alwaysdata": _3, + "myamaze": _3, + "cloudfront": _3, + "t3l3p0rt": _3, + "appudo": _3, + "atlassian-dev": [0, { + "prod": [0, { + "cdn": _3 + }] + }], + "myfritz": _3, + "onavstack": _3, + "shopselect": _3, + "blackbaudcdn": _3, + "boomla": _3, + "bplaced": _3, + "square7": _3, + "gb": _3, + "hu": _3, + "jp": _3, + "se": _3, + "uk": _3, + "in": _3, + "clickrising": _3, + "cloudaccess": _3, + "cdn77-ssl": _3, + "cdn77": [0, { + "r": _3 + }], + "feste-ip": _3, + "knx-server": _3, + "static-access": _3, + "cryptonomic": _5, + "dattolocal": _3, + "mydatto": _3, + "debian": _3, + "bitbridge": _3, + "at-band-camp": _3, + "blogdns": _3, + "broke-it": _3, + "buyshouses": _3, + "dnsalias": _3, + "dnsdojo": _3, + "does-it": _3, + "dontexist": _3, + "dynalias": _3, + "dynathome": _3, + "endofinternet": _3, + "from-az": _3, + "from-co": _3, + "from-la": _3, + "from-ny": _3, + "gets-it": _3, + "ham-radio-op": _3, + "homeftp": _3, + "homeip": _3, + "homelinux": _3, + "homeunix": _3, + "in-the-band": _3, + "is-a-chef": _3, + "is-a-geek": _3, + "isa-geek": _3, + "kicks-ass": _3, + "office-on-the": _3, + "podzone": _3, + "scrapper-site": _3, + "selfip": _3, + "sells-it": _3, + "servebbs": _3, + "serveftp": _3, + "thruhere": _3, + "webhop": _3, + "definima": _3, + "casacam": _3, + "dynu": _3, + "dynv6": _3, + "twmail": _3, + "ru": _3, + "channelsdvr": [2, { + "u": _3 + }], + "fastlylb": [2, { + "map": _3 + }], + "fastly": [0, { + "freetls": _3, + "map": _3, + "prod": [0, { + "a": _3, + "global": _3 + }], + "ssl": [0, { + "a": _3, + "b": _3, + "global": _3 + }] + }], + "edgeapp": _3, + "flynnhosting": _3, + "cdn-edges": _3, + "heteml": _3, + "cloudfunctions": _3, + "moonscale": _3, + "in-dsl": _3, + "in-vpn": _3, + "ipifony": _3, + "iobb": _3, + "cloudjiffy": [2, { + "fra1-de": _3, + "west1-us": _3 + }], + "elastx": [0, { + "jls-sto1": _3, + "jls-sto2": _3, + "jls-sto3": _3 + }], + "faststacks": _3, + "massivegrid": [0, { + "paas": [0, { + "fr-1": _3, + "lon-1": _3, + "lon-2": _3, + "ny-1": _3, + "ny-2": _3, + "sg-1": _3 + }] + }], + "saveincloud": [0, { + "jelastic": _3, + "nordeste-idc": _3 + }], + "scaleforce": _41, + "tsukaeru": _42, + "kinghost": _3, + "uni5": _3, + "krellian": _3, + "barsy": _3, + "memset": _3, + "azure-api": _3, + "azureedge": _3, + "azurefd": _3, + "azurewebsites": _3, + "azure-mobile": _3, + "azurestaticapps": [2, { + "1": _3, + "2": _3, + "3": _3, + "4": _3, + "5": _3, + "6": _3, + "7": _3, + "centralus": _3, + "eastasia": _3, + "eastus2": _3, + "westeurope": _3, + "westus2": _3 + }], + "cloudapp": _3, + "trafficmanager": _3, + "windows": [0, { + "core": [0, { + "blob": _3 + }], + "servicebus": _3 + }], + "dnsup": _3, + "hicam": _3, + "now-dns": _3, + "ownip": _3, + "vpndns": _3, + "eating-organic": _3, + "mydissent": _3, + "myeffect": _3, + "mymediapc": _3, + "mypsx": _3, + "mysecuritycamera": _3, + "nhlfan": _3, + "no-ip": _3, + "pgafan": _3, + "privatizehealthinsurance": _3, + "bounceme": _3, + "ddns": _3, + "redirectme": _3, + "serveblog": _3, + "serveminecraft": _3, + "sytes": _3, + "cloudycluster": _3, + "ovh": [0, { + "webpaas": _5, + "hosting": _5 + }], + "bar0": _3, + "bar1": _3, + "bar2": _3, + "myradweb": _3, + "rackmaze": _3, + "squares": _3, + "schokokeks": _3, + "firewall-gateway": _3, + "seidat": _3, + "senseering": _3, + "siteleaf": _3, + "vps-host": [2, { + "jelastic": [0, { + "atl": _3, + "njs": _3, + "ric": _3 + }] + }], + "myspreadshop": _3, + "srcf": [0, { + "soc": _3, + "user": _3 + }], + "supabase": _3, + "dsmynas": _3, + "familyds": _3, + "tailscale": [0, { + "beta": _3 + }], + "ts": [2, { + "c": _5 + }], + "torproject": [2, { + "pages": _3 + }], + "reserve-online": _3, + "community-pro": _3, + "meinforum": _3, + "yandexcloud": [2, { + "storage": _3, + "website": _3 + }], + "za": _3 + }], + "nf": [1, { + "com": _2, + "net": _2, + "per": _2, + "rec": _2, + "web": _2, + "arts": _2, + "firm": _2, + "info": _2, + "other": _2, + "store": _2 + }], + "ng": [1, { + "com": _7, + "edu": _2, + "gov": _2, + "i": _2, + "mil": _2, + "mobi": _2, + "name": _2, + "net": _2, + "org": _2, + "sch": _2, + "col": _3, + "firm": _3, + "gen": _3, + "ltd": _3, + "ngo": _3 + }], + "ni": [1, { + "ac": _2, + "biz": _2, + "co": _2, + "com": _2, + "edu": _2, + "gob": _2, + "in": _2, + "info": _2, + "int": _2, + "mil": _2, + "net": _2, + "nom": _2, + "org": _2, + "web": _2 + }], + "nl": [1, { + "co": _3, + "hosting-cluster": _3, + "blogspot": _3, + "gov": _3, + "khplay": _3, + "123website": _3, + "myspreadshop": _3, + "transurl": _5, + "cistron": _3, + "demon": _3 + }], + "no": [1, { + "fhs": _2, + "vgs": _2, + "fylkesbibl": _2, + "folkebibl": _2, + "museum": _2, + "idrett": _2, + "priv": _2, + "mil": _2, + "stat": _2, + "dep": _2, + "kommune": _2, + "herad": _2, + "aa": _54, + "ah": _54, + "bu": _54, + "fm": _54, + "hl": _54, + "hm": _54, + "jan-mayen": _54, + "mr": _54, + "nl": _54, + "nt": _54, + "of": _54, + "ol": _54, + "oslo": _54, + "rl": _54, + "sf": _54, + "st": _54, + "svalbard": _54, + "tm": _54, + "tr": _54, + "va": _54, + "vf": _54, + "akrehamn": _2, + "xn--krehamn-dxa": _2, + "Ã¥krehamn": _2, + "algard": _2, + "xn--lgrd-poac": _2, + "Ã¥lgÃ¥rd": _2, + "arna": _2, + "brumunddal": _2, + "bryne": _2, + "bronnoysund": _2, + "xn--brnnysund-m8ac": _2, + "brønnøysund": _2, + "drobak": _2, + "xn--drbak-wua": _2, + "drøbak": _2, + "egersund": _2, + "fetsund": _2, + "floro": _2, + "xn--flor-jra": _2, + "florø": _2, + "fredrikstad": _2, + "hokksund": _2, + "honefoss": _2, + "xn--hnefoss-q1a": _2, + "hønefoss": _2, + "jessheim": _2, + "jorpeland": _2, + "xn--jrpeland-54a": _2, + "jørpeland": _2, + "kirkenes": _2, + "kopervik": _2, + "krokstadelva": _2, + "langevag": _2, + "xn--langevg-jxa": _2, + "langevÃ¥g": _2, + "leirvik": _2, + "mjondalen": _2, + "xn--mjndalen-64a": _2, + "mjøndalen": _2, + "mo-i-rana": _2, + "mosjoen": _2, + "xn--mosjen-eya": _2, + "mosjøen": _2, + "nesoddtangen": _2, + "orkanger": _2, + "osoyro": _2, + "xn--osyro-wua": _2, + "osøyro": _2, + "raholt": _2, + "xn--rholt-mra": _2, + "rÃ¥holt": _2, + "sandnessjoen": _2, + "xn--sandnessjen-ogb": _2, + "sandnessjøen": _2, + "skedsmokorset": _2, + "slattum": _2, + "spjelkavik": _2, + "stathelle": _2, + "stavern": _2, + "stjordalshalsen": _2, + "xn--stjrdalshalsen-sqb": _2, + "stjørdalshalsen": _2, + "tananger": _2, + "tranby": _2, + "vossevangen": _2, + "afjord": _2, + "xn--fjord-lra": _2, + "Ã¥fjord": _2, + "agdenes": _2, + "al": _2, + "xn--l-1fa": _2, + "Ã¥l": _2, + "alesund": _2, + "xn--lesund-hua": _2, + "Ã¥lesund": _2, + "alstahaug": _2, + "alta": _2, + "xn--lt-liac": _2, + "áltá": _2, + "alaheadju": _2, + "xn--laheadju-7ya": _2, + "álaheadju": _2, + "alvdal": _2, + "amli": _2, + "xn--mli-tla": _2, + "Ã¥mli": _2, + "amot": _2, + "xn--mot-tla": _2, + "Ã¥mot": _2, + "andebu": _2, + "andoy": _2, + "xn--andy-ira": _2, + "andøy": _2, + "andasuolo": _2, + "ardal": _2, + "xn--rdal-poa": _2, + "Ã¥rdal": _2, + "aremark": _2, + "arendal": _2, + "xn--s-1fa": _2, + "Ã¥s": _2, + "aseral": _2, + "xn--seral-lra": _2, + "Ã¥seral": _2, + "asker": _2, + "askim": _2, + "askvoll": _2, + "askoy": _2, + "xn--asky-ira": _2, + "askøy": _2, + "asnes": _2, + "xn--snes-poa": _2, + "Ã¥snes": _2, + "audnedaln": _2, + "aukra": _2, + "aure": _2, + "aurland": _2, + "aurskog-holand": _2, + "xn--aurskog-hland-jnb": _2, + "aurskog-høland": _2, + "austevoll": _2, + "austrheim": _2, + "averoy": _2, + "xn--avery-yua": _2, + "averøy": _2, + "balestrand": _2, + "ballangen": _2, + "balat": _2, + "xn--blt-elab": _2, + "bálát": _2, + "balsfjord": _2, + "bahccavuotna": _2, + "xn--bhccavuotna-k7a": _2, + "báhccavuotna": _2, + "bamble": _2, + "bardu": _2, + "beardu": _2, + "beiarn": _2, + "bajddar": _2, + "xn--bjddar-pta": _2, + "bájddar": _2, + "baidar": _2, + "xn--bidr-5nac": _2, + "báidár": _2, + "berg": _2, + "bergen": _2, + "berlevag": _2, + "xn--berlevg-jxa": _2, + "berlevÃ¥g": _2, + "bearalvahki": _2, + "xn--bearalvhki-y4a": _2, + "bearalváhki": _2, + "bindal": _2, + "birkenes": _2, + "bjarkoy": _2, + "xn--bjarky-fya": _2, + "bjarkøy": _2, + "bjerkreim": _2, + "bjugn": _2, + "bodo": _2, + "xn--bod-2na": _2, + "bodø": _2, + "badaddja": _2, + "xn--bdddj-mrabd": _2, + "bÃ¥dÃ¥ddjÃ¥": _2, + "budejju": _2, + "bokn": _2, + "bremanger": _2, + "bronnoy": _2, + "xn--brnny-wuac": _2, + "brønnøy": _2, + "bygland": _2, + "bykle": _2, + "barum": _2, + "xn--brum-voa": _2, + "bærum": _2, + "telemark": [0, { + "bo": _2, + "xn--b-5ga": _2, + "bø": _2 + }], + "nordland": [0, { + "bo": _2, + "xn--b-5ga": _2, + "bø": _2, + "heroy": _2, + "xn--hery-ira": _2, + "herøy": _2 + }], + "bievat": _2, + "xn--bievt-0qa": _2, + "bievát": _2, + "bomlo": _2, + "xn--bmlo-gra": _2, + "bømlo": _2, + "batsfjord": _2, + "xn--btsfjord-9za": _2, + "bÃ¥tsfjord": _2, + "bahcavuotna": _2, + "xn--bhcavuotna-s4a": _2, + "báhcavuotna": _2, + "dovre": _2, + "drammen": _2, + "drangedal": _2, + "dyroy": _2, + "xn--dyry-ira": _2, + "dyrøy": _2, + "donna": _2, + "xn--dnna-gra": _2, + "dønna": _2, + "eid": _2, + "eidfjord": _2, + "eidsberg": _2, + "eidskog": _2, + "eidsvoll": _2, + "eigersund": _2, + "elverum": _2, + "enebakk": _2, + "engerdal": _2, + "etne": _2, + "etnedal": _2, + "evenes": _2, + "evenassi": _2, + "xn--eveni-0qa01ga": _2, + "evenášši": _2, + "evje-og-hornnes": _2, + "farsund": _2, + "fauske": _2, + "fuossko": _2, + "fuoisku": _2, + "fedje": _2, + "fet": _2, + "finnoy": _2, + "xn--finny-yua": _2, + "finnøy": _2, + "fitjar": _2, + "fjaler": _2, + "fjell": _2, + "flakstad": _2, + "flatanger": _2, + "flekkefjord": _2, + "flesberg": _2, + "flora": _2, + "fla": _2, + "xn--fl-zia": _2, + "flÃ¥": _2, + "folldal": _2, + "forsand": _2, + "fosnes": _2, + "frei": _2, + "frogn": _2, + "froland": _2, + "frosta": _2, + "frana": _2, + "xn--frna-woa": _2, + "fræna": _2, + "froya": _2, + "xn--frya-hra": _2, + "frøya": _2, + "fusa": _2, + "fyresdal": _2, + "forde": _2, + "xn--frde-gra": _2, + "førde": _2, + "gamvik": _2, + "gangaviika": _2, + "xn--ggaviika-8ya47h": _2, + "gáŋgaviika": _2, + "gaular": _2, + "gausdal": _2, + "gildeskal": _2, + "xn--gildeskl-g0a": _2, + "gildeskÃ¥l": _2, + "giske": _2, + "gjemnes": _2, + "gjerdrum": _2, + "gjerstad": _2, + "gjesdal": _2, + "gjovik": _2, + "xn--gjvik-wua": _2, + "gjøvik": _2, + "gloppen": _2, + "gol": _2, + "gran": _2, + "grane": _2, + "granvin": _2, + "gratangen": _2, + "grimstad": _2, + "grong": _2, + "kraanghke": _2, + "xn--kranghke-b0a": _2, + "krÃ¥anghke": _2, + "grue": _2, + "gulen": _2, + "hadsel": _2, + "halden": _2, + "halsa": _2, + "hamar": _2, + "hamaroy": _2, + "habmer": _2, + "xn--hbmer-xqa": _2, + "hábmer": _2, + "hapmir": _2, + "xn--hpmir-xqa": _2, + "hápmir": _2, + "hammerfest": _2, + "hammarfeasta": _2, + "xn--hmmrfeasta-s4ac": _2, + "hámmárfeasta": _2, + "haram": _2, + "hareid": _2, + "harstad": _2, + "hasvik": _2, + "aknoluokta": _2, + "xn--koluokta-7ya57h": _2, + "ákÅ‹oluokta": _2, + "hattfjelldal": _2, + "aarborte": _2, + "haugesund": _2, + "hemne": _2, + "hemnes": _2, + "hemsedal": _2, + "more-og-romsdal": [0, { + "heroy": _2, + "sande": _2 + }], + "xn--mre-og-romsdal-qqb": [0, { + "xn--hery-ira": _2, + "sande": _2 + }], + "møre-og-romsdal": [0, { + "herøy": _2, + "sande": _2 + }], + "hitra": _2, + "hjartdal": _2, + "hjelmeland": _2, + "hobol": _2, + "xn--hobl-ira": _2, + "hobøl": _2, + "hof": _2, + "hol": _2, + "hole": _2, + "holmestrand": _2, + "holtalen": _2, + "xn--holtlen-hxa": _2, + "holtÃ¥len": _2, + "hornindal": _2, + "horten": _2, + "hurdal": _2, + "hurum": _2, + "hvaler": _2, + "hyllestad": _2, + "hagebostad": _2, + "xn--hgebostad-g3a": _2, + "hægebostad": _2, + "hoyanger": _2, + "xn--hyanger-q1a": _2, + "høyanger": _2, + "hoylandet": _2, + "xn--hylandet-54a": _2, + "høylandet": _2, + "ha": _2, + "xn--h-2fa": _2, + "hÃ¥": _2, + "ibestad": _2, + "inderoy": _2, + "xn--indery-fya": _2, + "inderøy": _2, + "iveland": _2, + "jevnaker": _2, + "jondal": _2, + "jolster": _2, + "xn--jlster-bya": _2, + "jølster": _2, + "karasjok": _2, + "karasjohka": _2, + "xn--krjohka-hwab49j": _2, + "kárášjohka": _2, + "karlsoy": _2, + "galsa": _2, + "xn--gls-elac": _2, + "gálsá": _2, + "karmoy": _2, + "xn--karmy-yua": _2, + "karmøy": _2, + "kautokeino": _2, + "guovdageaidnu": _2, + "klepp": _2, + "klabu": _2, + "xn--klbu-woa": _2, + "klæbu": _2, + "kongsberg": _2, + "kongsvinger": _2, + "kragero": _2, + "xn--krager-gya": _2, + "kragerø": _2, + "kristiansand": _2, + "kristiansund": _2, + "krodsherad": _2, + "xn--krdsherad-m8a": _2, + "krødsherad": _2, + "kvalsund": _2, + "rahkkeravju": _2, + "xn--rhkkervju-01af": _2, + "ráhkkerávju": _2, + "kvam": _2, + "kvinesdal": _2, + "kvinnherad": _2, + "kviteseid": _2, + "kvitsoy": _2, + "xn--kvitsy-fya": _2, + "kvitsøy": _2, + "kvafjord": _2, + "xn--kvfjord-nxa": _2, + "kvæfjord": _2, + "giehtavuoatna": _2, + "kvanangen": _2, + "xn--kvnangen-k0a": _2, + "kvænangen": _2, + "navuotna": _2, + "xn--nvuotna-hwa": _2, + "návuotna": _2, + "kafjord": _2, + "xn--kfjord-iua": _2, + "kÃ¥fjord": _2, + "gaivuotna": _2, + "xn--givuotna-8ya": _2, + "gáivuotna": _2, + "larvik": _2, + "lavangen": _2, + "lavagis": _2, + "loabat": _2, + "xn--loabt-0qa": _2, + "loabát": _2, + "lebesby": _2, + "davvesiida": _2, + "leikanger": _2, + "leirfjord": _2, + "leka": _2, + "leksvik": _2, + "lenvik": _2, + "leangaviika": _2, + "xn--leagaviika-52b": _2, + "leaÅ‹gaviika": _2, + "lesja": _2, + "levanger": _2, + "lier": _2, + "lierne": _2, + "lillehammer": _2, + "lillesand": _2, + "lindesnes": _2, + "lindas": _2, + "xn--linds-pra": _2, + "lindÃ¥s": _2, + "lom": _2, + "loppa": _2, + "lahppi": _2, + "xn--lhppi-xqa": _2, + "láhppi": _2, + "lund": _2, + "lunner": _2, + "luroy": _2, + "xn--lury-ira": _2, + "lurøy": _2, + "luster": _2, + "lyngdal": _2, + "lyngen": _2, + "ivgu": _2, + "lardal": _2, + "lerdal": _2, + "xn--lrdal-sra": _2, + "lærdal": _2, + "lodingen": _2, + "xn--ldingen-q1a": _2, + "lødingen": _2, + "lorenskog": _2, + "xn--lrenskog-54a": _2, + "lørenskog": _2, + "loten": _2, + "xn--lten-gra": _2, + "løten": _2, + "malvik": _2, + "masoy": _2, + "xn--msy-ula0h": _2, + "mÃ¥søy": _2, + "muosat": _2, + "xn--muost-0qa": _2, + "muosát": _2, + "mandal": _2, + "marker": _2, + "marnardal": _2, + "masfjorden": _2, + "meland": _2, + "meldal": _2, + "melhus": _2, + "meloy": _2, + "xn--mely-ira": _2, + "meløy": _2, + "meraker": _2, + "xn--merker-kua": _2, + "merÃ¥ker": _2, + "moareke": _2, + "xn--moreke-jua": _2, + "moÃ¥reke": _2, + "midsund": _2, + "midtre-gauldal": _2, + "modalen": _2, + "modum": _2, + "molde": _2, + "moskenes": _2, + "moss": _2, + "mosvik": _2, + "malselv": _2, + "xn--mlselv-iua": _2, + "mÃ¥lselv": _2, + "malatvuopmi": _2, + "xn--mlatvuopmi-s4a": _2, + "málatvuopmi": _2, + "namdalseid": _2, + "aejrie": _2, + "namsos": _2, + "namsskogan": _2, + "naamesjevuemie": _2, + "xn--nmesjevuemie-tcba": _2, + "nååmesjevuemie": _2, + "laakesvuemie": _2, + "nannestad": _2, + "narvik": _2, + "narviika": _2, + "naustdal": _2, + "nedre-eiker": _2, + "akershus": _55, + "buskerud": _55, + "nesna": _2, + "nesodden": _2, + "nesseby": _2, + "unjarga": _2, + "xn--unjrga-rta": _2, + "unjárga": _2, + "nesset": _2, + "nissedal": _2, + "nittedal": _2, + "nord-aurdal": _2, + "nord-fron": _2, + "nord-odal": _2, + "norddal": _2, + "nordkapp": _2, + "davvenjarga": _2, + "xn--davvenjrga-y4a": _2, + "davvenjárga": _2, + "nordre-land": _2, + "nordreisa": _2, + "raisa": _2, + "xn--risa-5na": _2, + "ráisa": _2, + "nore-og-uvdal": _2, + "notodden": _2, + "naroy": _2, + "xn--nry-yla5g": _2, + "nærøy": _2, + "notteroy": _2, + "xn--nttery-byae": _2, + "nøtterøy": _2, + "odda": _2, + "oksnes": _2, + "xn--ksnes-uua": _2, + "øksnes": _2, + "oppdal": _2, + "oppegard": _2, + "xn--oppegrd-ixa": _2, + "oppegÃ¥rd": _2, + "orkdal": _2, + "orland": _2, + "xn--rland-uua": _2, + "ørland": _2, + "orskog": _2, + "xn--rskog-uua": _2, + "ørskog": _2, + "orsta": _2, + "xn--rsta-fra": _2, + "ørsta": _2, + "hedmark": [0, { + "os": _2, + "valer": _2, + "xn--vler-qoa": _2, + "vÃ¥ler": _2 + }], + "hordaland": [0, { + "os": _2 + }], + "osen": _2, + "osteroy": _2, + "xn--ostery-fya": _2, + "osterøy": _2, + "ostre-toten": _2, + "xn--stre-toten-zcb": _2, + "østre-toten": _2, + "overhalla": _2, + "ovre-eiker": _2, + "xn--vre-eiker-k8a": _2, + "øvre-eiker": _2, + "oyer": _2, + "xn--yer-zna": _2, + "øyer": _2, + "oygarden": _2, + "xn--ygarden-p1a": _2, + "øygarden": _2, + "oystre-slidre": _2, + "xn--ystre-slidre-ujb": _2, + "øystre-slidre": _2, + "porsanger": _2, + "porsangu": _2, + "xn--porsgu-sta26f": _2, + "porsáŋgu": _2, + "porsgrunn": _2, + "radoy": _2, + "xn--rady-ira": _2, + "radøy": _2, + "rakkestad": _2, + "rana": _2, + "ruovat": _2, + "randaberg": _2, + "rauma": _2, + "rendalen": _2, + "rennebu": _2, + "rennesoy": _2, + "xn--rennesy-v1a": _2, + "rennesøy": _2, + "rindal": _2, + "ringebu": _2, + "ringerike": _2, + "ringsaker": _2, + "rissa": _2, + "risor": _2, + "xn--risr-ira": _2, + "risør": _2, + "roan": _2, + "rollag": _2, + "rygge": _2, + "ralingen": _2, + "xn--rlingen-mxa": _2, + "rælingen": _2, + "rodoy": _2, + "xn--rdy-0nab": _2, + "rødøy": _2, + "romskog": _2, + "xn--rmskog-bya": _2, + "rømskog": _2, + "roros": _2, + "xn--rros-gra": _2, + "røros": _2, + "rost": _2, + "xn--rst-0na": _2, + "røst": _2, + "royken": _2, + "xn--ryken-vua": _2, + "røyken": _2, + "royrvik": _2, + "xn--ryrvik-bya": _2, + "røyrvik": _2, + "rade": _2, + "xn--rde-ula": _2, + "rÃ¥de": _2, + "salangen": _2, + "siellak": _2, + "saltdal": _2, + "salat": _2, + "xn--slt-elab": _2, + "sálát": _2, + "xn--slat-5na": _2, + "sálat": _2, + "samnanger": _2, + "vestfold": [0, { + "sande": _2 + }], + "sandefjord": _2, + "sandnes": _2, + "sandoy": _2, + "xn--sandy-yua": _2, + "sandøy": _2, + "sarpsborg": _2, + "sauda": _2, + "sauherad": _2, + "sel": _2, + "selbu": _2, + "selje": _2, + "seljord": _2, + "sigdal": _2, + "siljan": _2, + "sirdal": _2, + "skaun": _2, + "skedsmo": _2, + "ski": _2, + "skien": _2, + "skiptvet": _2, + "skjervoy": _2, + "xn--skjervy-v1a": _2, + "skjervøy": _2, + "skierva": _2, + "xn--skierv-uta": _2, + "skiervá": _2, + "skjak": _2, + "xn--skjk-soa": _2, + "skjÃ¥k": _2, + "skodje": _2, + "skanland": _2, + "xn--sknland-fxa": _2, + "skÃ¥nland": _2, + "skanit": _2, + "xn--sknit-yqa": _2, + "skánit": _2, + "smola": _2, + "xn--smla-hra": _2, + "smøla": _2, + "snillfjord": _2, + "snasa": _2, + "xn--snsa-roa": _2, + "snÃ¥sa": _2, + "snoasa": _2, + "snaase": _2, + "xn--snase-nra": _2, + "snÃ¥ase": _2, + "sogndal": _2, + "sokndal": _2, + "sola": _2, + "solund": _2, + "songdalen": _2, + "sortland": _2, + "spydeberg": _2, + "stange": _2, + "stavanger": _2, + "steigen": _2, + "steinkjer": _2, + "stjordal": _2, + "xn--stjrdal-s1a": _2, + "stjørdal": _2, + "stokke": _2, + "stor-elvdal": _2, + "stord": _2, + "stordal": _2, + "storfjord": _2, + "omasvuotna": _2, + "strand": _2, + "stranda": _2, + "stryn": _2, + "sula": _2, + "suldal": _2, + "sund": _2, + "sunndal": _2, + "surnadal": _2, + "sveio": _2, + "svelvik": _2, + "sykkylven": _2, + "sogne": _2, + "xn--sgne-gra": _2, + "søgne": _2, + "somna": _2, + "xn--smna-gra": _2, + "sømna": _2, + "sondre-land": _2, + "xn--sndre-land-0cb": _2, + "søndre-land": _2, + "sor-aurdal": _2, + "xn--sr-aurdal-l8a": _2, + "sør-aurdal": _2, + "sor-fron": _2, + "xn--sr-fron-q1a": _2, + "sør-fron": _2, + "sor-odal": _2, + "xn--sr-odal-q1a": _2, + "sør-odal": _2, + "sor-varanger": _2, + "xn--sr-varanger-ggb": _2, + "sør-varanger": _2, + "matta-varjjat": _2, + "xn--mtta-vrjjat-k7af": _2, + "mátta-várjjat": _2, + "sorfold": _2, + "xn--srfold-bya": _2, + "sørfold": _2, + "sorreisa": _2, + "xn--srreisa-q1a": _2, + "sørreisa": _2, + "sorum": _2, + "xn--srum-gra": _2, + "sørum": _2, + "tana": _2, + "deatnu": _2, + "time": _2, + "tingvoll": _2, + "tinn": _2, + "tjeldsund": _2, + "dielddanuorri": _2, + "tjome": _2, + "xn--tjme-hra": _2, + "tjøme": _2, + "tokke": _2, + "tolga": _2, + "torsken": _2, + "tranoy": _2, + "xn--trany-yua": _2, + "tranøy": _2, + "tromso": _2, + "xn--troms-zua": _2, + "tromsø": _2, + "tromsa": _2, + "romsa": _2, + "trondheim": _2, + "troandin": _2, + "trysil": _2, + "trana": _2, + "xn--trna-woa": _2, + "træna": _2, + "trogstad": _2, + "xn--trgstad-r1a": _2, + "trøgstad": _2, + "tvedestrand": _2, + "tydal": _2, + "tynset": _2, + "tysfjord": _2, + "divtasvuodna": _2, + "divttasvuotna": _2, + "tysnes": _2, + "tysvar": _2, + "xn--tysvr-vra": _2, + "tysvær": _2, + "tonsberg": _2, + "xn--tnsberg-q1a": _2, + "tønsberg": _2, + "ullensaker": _2, + "ullensvang": _2, + "ulvik": _2, + "utsira": _2, + "vadso": _2, + "xn--vads-jra": _2, + "vadsø": _2, + "cahcesuolo": _2, + "xn--hcesuolo-7ya35b": _2, + "Äáhcesuolo": _2, + "vaksdal": _2, + "valle": _2, + "vang": _2, + "vanylven": _2, + "vardo": _2, + "xn--vard-jra": _2, + "vardø": _2, + "varggat": _2, + "xn--vrggt-xqad": _2, + "várggát": _2, + "vefsn": _2, + "vaapste": _2, + "vega": _2, + "vegarshei": _2, + "xn--vegrshei-c0a": _2, + "vegÃ¥rshei": _2, + "vennesla": _2, + "verdal": _2, + "verran": _2, + "vestby": _2, + "vestnes": _2, + "vestre-slidre": _2, + "vestre-toten": _2, + "vestvagoy": _2, + "xn--vestvgy-ixa6o": _2, + "vestvÃ¥gøy": _2, + "vevelstad": _2, + "vik": _2, + "vikna": _2, + "vindafjord": _2, + "volda": _2, + "voss": _2, + "varoy": _2, + "xn--vry-yla5g": _2, + "værøy": _2, + "vagan": _2, + "xn--vgan-qoa": _2, + "vÃ¥gan": _2, + "voagat": _2, + "vagsoy": _2, + "xn--vgsy-qoa0j": _2, + "vÃ¥gsøy": _2, + "vaga": _2, + "xn--vg-yiab": _2, + "vÃ¥gÃ¥": _2, + "ostfold": [0, { + "valer": _2 + }], + "xn--stfold-9xa": [0, { + "xn--vler-qoa": _2 + }], + "østfold": [0, { + "vÃ¥ler": _2 + }], + "co": _3, + "blogspot": _3, + "123hjemmeside": _3, + "myspreadshop": _3 + }], + "np": _13, + "nr": _49, + "nu": [1, { + "merseine": _3, + "mine": _3, + "shacknet": _3, + "enterprisecloud": _3 + }], + "nz": [1, { + "ac": _2, + "co": _7, + "cri": _2, + "geek": _2, + "gen": _2, + "govt": _2, + "health": _2, + "iwi": _2, + "kiwi": _2, + "maori": _2, + "mil": _2, + "xn--mori-qsa": _2, + "mÄori": _2, + "net": _2, + "org": _2, + "parliament": _2, + "school": _2 + }], + "om": [1, { + "co": _2, + "com": _2, + "edu": _2, + "gov": _2, + "med": _2, + "museum": _2, + "net": _2, + "org": _2, + "pro": _2 + }], + "onion": _2, + "org": [1, { + "altervista": _3, + "amune": [0, { + "tele": _3 + }], + "pimienta": _3, + "poivron": _3, + "potager": _3, + "sweetpepper": _3, + "ae": _3, + "us": _3, + "certmgr": _3, + "cdn77": [0, { + "c": _3, + "rsc": _3 + }], + "cdn77-secure": [0, { + "origin": [0, { + "ssl": _3 + }] + }], + "cloudns": _3, + "duckdns": _3, + "tunk": _3, + "dyndns": [2, { + "go": _3, + "home": _3 + }], + "blogdns": _3, + "blogsite": _3, + "boldlygoingnowhere": _3, + "dnsalias": _3, + "dnsdojo": _3, + "doesntexist": _3, + "dontexist": _3, + "doomdns": _3, + "dvrdns": _3, + "dynalias": _3, + "endofinternet": _3, + "endoftheinternet": _3, + "from-me": _3, + "game-host": _3, + "gotdns": _3, + "hobby-site": _3, + "homedns": _3, + "homeftp": _3, + "homelinux": _3, + "homeunix": _3, + "is-a-bruinsfan": _3, + "is-a-candidate": _3, + "is-a-celticsfan": _3, + "is-a-chef": _3, + "is-a-geek": _3, + "is-a-knight": _3, + "is-a-linux-user": _3, + "is-a-patsfan": _3, + "is-a-soxfan": _3, + "is-found": _3, + "is-lost": _3, + "is-saved": _3, + "is-very-bad": _3, + "is-very-evil": _3, + "is-very-good": _3, + "is-very-nice": _3, + "is-very-sweet": _3, + "isa-geek": _3, + "kicks-ass": _3, + "misconfused": _3, + "podzone": _3, + "readmyblog": _3, + "selfip": _3, + "sellsyourhome": _3, + "servebbs": _3, + "serveftp": _3, + "servegame": _3, + "stuff-4-sale": _3, + "webhop": _3, + "ddnss": _3, + "accesscam": _3, + "camdvr": _3, + "freeddns": _3, + "mywire": _3, + "webredirect": _3, + "eu": [2, { + "al": _3, + "asso": _3, + "at": _3, + "au": _3, + "be": _3, + "bg": _3, + "ca": _3, + "cd": _3, + "ch": _3, + "cn": _3, + "cy": _3, + "cz": _3, + "de": _3, + "dk": _3, + "edu": _3, + "ee": _3, + "es": _3, + "fi": _3, + "fr": _3, + "gr": _3, + "hr": _3, + "hu": _3, + "ie": _3, + "il": _3, + "in": _3, + "int": _3, + "is": _3, + "it": _3, + "jp": _3, + "kr": _3, + "lt": _3, + "lu": _3, + "lv": _3, + "mc": _3, + "me": _3, + "mk": _3, + "mt": _3, + "my": _3, + "net": _3, + "ng": _3, + "nl": _3, + "no": _3, + "nz": _3, + "paris": _3, + "pl": _3, + "pt": _3, + "q-a": _3, + "ro": _3, + "ru": _3, + "se": _3, + "si": _3, + "sk": _3, + "tr": _3, + "uk": _3, + "us": _3 + }], + "twmail": _3, + "fedorainfracloud": _3, + "fedorapeople": _3, + "fedoraproject": [0, { + "cloud": _3, + "os": _36, + "stg": [0, { + "os": _36 + }] + }], + "freedesktop": _3, + "hepforge": _3, + "in-dsl": _3, + "in-vpn": _3, + "js": _3, + "barsy": _3, + "mayfirst": _3, + "mozilla-iot": _3, + "bmoattachments": _3, + "dynserv": _3, + "now-dns": _3, + "cable-modem": _3, + "collegefan": _3, + "couchpotatofries": _3, + "mlbfan": _3, + "mysecuritycamera": _3, + "nflfan": _3, + "read-books": _3, + "ufcfan": _3, + "hopto": _3, + "myftp": _3, + "no-ip": _3, + "zapto": _3, + "httpbin": _3, + "pubtls": _3, + "jpn": _3, + "my-firewall": _3, + "myfirewall": _3, + "spdns": _3, + "small-web": _3, + "dsmynas": _3, + "familyds": _3, + "teckids": _48, + "tuxfamily": _3, + "diskstation": _3, + "hk": _3, + "wmflabs": _3, + "toolforge": _3, + "wmcloud": _3, + "za": _3 + }], + "pa": [1, { + "ac": _2, + "gob": _2, + "com": _2, + "org": _2, + "sld": _2, + "edu": _2, + "net": _2, + "ing": _2, + "abo": _2, + "med": _2, + "nom": _2 + }], + "pe": [1, { + "edu": _2, + "gob": _2, + "nom": _2, + "mil": _2, + "org": _2, + "com": _2, + "net": _2, + "blogspot": _3 + }], + "pf": [1, { + "com": _2, + "org": _2, + "edu": _2 + }], + "pg": _13, + "ph": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "edu": _2, + "ngo": _2, + "mil": _2, + "i": _2 + }], + "pk": [1, { + "com": _2, + "net": _2, + "edu": _2, + "org": _2, + "fam": _2, + "biz": _2, + "web": _2, + "gov": _2, + "gob": _2, + "gok": _2, + "gon": _2, + "gop": _2, + "gos": _2, + "info": _2 + }], + "pl": [1, { + "com": _2, + "net": _2, + "org": _2, + "aid": _2, + "agro": _2, + "atm": _2, + "auto": _2, + "biz": _2, + "edu": _2, + "gmina": _2, + "gsm": _2, + "info": _2, + "mail": _2, + "miasta": _2, + "media": _2, + "mil": _2, + "nieruchomosci": _2, + "nom": _2, + "pc": _2, + "powiat": _2, + "priv": _2, + "realestate": _2, + "rel": _2, + "sex": _2, + "shop": _2, + "sklep": _2, + "sos": _2, + "szkola": _2, + "targi": _2, + "tm": _2, + "tourism": _2, + "travel": _2, + "turystyka": _2, + "gov": [1, { + "ap": _2, + "griw": _2, + "ic": _2, + "is": _2, + "kmpsp": _2, + "konsulat": _2, + "kppsp": _2, + "kwp": _2, + "kwpsp": _2, + "mup": _2, + "mw": _2, + "oia": _2, + "oirm": _2, + "oke": _2, + "oow": _2, + "oschr": _2, + "oum": _2, + "pa": _2, + "pinb": _2, + "piw": _2, + "po": _2, + "pr": _2, + "psp": _2, + "psse": _2, + "pup": _2, + "rzgw": _2, + "sa": _2, + "sdn": _2, + "sko": _2, + "so": _2, + "sr": _2, + "starostwo": _2, + "ug": _2, + "ugim": _2, + "um": _2, + "umig": _2, + "upow": _2, + "uppo": _2, + "us": _2, + "uw": _2, + "uzs": _2, + "wif": _2, + "wiih": _2, + "winb": _2, + "wios": _2, + "witd": _2, + "wiw": _2, + "wkz": _2, + "wsa": _2, + "wskr": _2, + "wsse": _2, + "wuoz": _2, + "wzmiuw": _2, + "zp": _2, + "zpisdn": _2 + }], + "augustow": _2, + "babia-gora": _2, + "bedzin": _2, + "beskidy": _2, + "bialowieza": _2, + "bialystok": _2, + "bielawa": _2, + "bieszczady": _2, + "boleslawiec": _2, + "bydgoszcz": _2, + "bytom": _2, + "cieszyn": _2, + "czeladz": _2, + "czest": _2, + "dlugoleka": _2, + "elblag": _2, + "elk": _2, + "glogow": _2, + "gniezno": _2, + "gorlice": _2, + "grajewo": _2, + "ilawa": _2, + "jaworzno": _2, + "jelenia-gora": _2, + "jgora": _2, + "kalisz": _2, + "kazimierz-dolny": _2, + "karpacz": _2, + "kartuzy": _2, + "kaszuby": _2, + "katowice": _2, + "kepno": _2, + "ketrzyn": _2, + "klodzko": _2, + "kobierzyce": _2, + "kolobrzeg": _2, + "konin": _2, + "konskowola": _2, + "kutno": _2, + "lapy": _2, + "lebork": _2, + "legnica": _2, + "lezajsk": _2, + "limanowa": _2, + "lomza": _2, + "lowicz": _2, + "lubin": _2, + "lukow": _2, + "malbork": _2, + "malopolska": _2, + "mazowsze": _2, + "mazury": _2, + "mielec": _2, + "mielno": _2, + "mragowo": _2, + "naklo": _2, + "nowaruda": _2, + "nysa": _2, + "olawa": _2, + "olecko": _2, + "olkusz": _2, + "olsztyn": _2, + "opoczno": _2, + "opole": _2, + "ostroda": _2, + "ostroleka": _2, + "ostrowiec": _2, + "ostrowwlkp": _2, + "pila": _2, + "pisz": _2, + "podhale": _2, + "podlasie": _2, + "polkowice": _2, + "pomorze": _2, + "pomorskie": _2, + "prochowice": _2, + "pruszkow": _2, + "przeworsk": _2, + "pulawy": _2, + "radom": _2, + "rawa-maz": _2, + "rybnik": _2, + "rzeszow": _2, + "sanok": _2, + "sejny": _2, + "slask": _2, + "slupsk": _2, + "sosnowiec": _2, + "stalowa-wola": _2, + "skoczow": _2, + "starachowice": _2, + "stargard": _2, + "suwalki": _2, + "swidnica": _2, + "swiebodzin": _2, + "swinoujscie": _2, + "szczecin": _2, + "szczytno": _2, + "tarnobrzeg": _2, + "tgory": _2, + "turek": _2, + "tychy": _2, + "ustka": _2, + "walbrzych": _2, + "warmia": _2, + "warszawa": _2, + "waw": _2, + "wegrow": _2, + "wielun": _2, + "wlocl": _2, + "wloclawek": _2, + "wodzislaw": _2, + "wolomin": _2, + "wroclaw": _2, + "zachpomor": _2, + "zagan": _2, + "zarow": _2, + "zgora": _2, + "zgorzelec": _2, + "beep": _3, + "ecommerce-shop": _3, + "shoparena": _3, + "homesklep": _3, + "sdscloud": _3, + "unicloud": _3, + "krasnik": _3, + "leczna": _3, + "lubartow": _3, + "lublin": _3, + "poniatowa": _3, + "swidnik": _3, + "co": _3, + "torun": _3, + "simplesite": _3, + "art": _3, + "gliwice": _3, + "krakow": _3, + "poznan": _3, + "wroc": _3, + "zakopane": _3, + "myspreadshop": _3, + "gda": _3, + "gdansk": _3, + "gdynia": _3, + "med": _3, + "sopot": _3 + }], + "pm": [1, { + "own": _3, + "name": _3 + }], + "pn": [1, { + "gov": _2, + "co": _2, + "org": _2, + "edu": _2, + "net": _2 + }], + "post": _2, + "pr": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "edu": _2, + "isla": _2, + "pro": _2, + "biz": _2, + "info": _2, + "name": _2, + "est": _2, + "prof": _2, + "ac": _2 + }], + "pro": [1, { + "aaa": _2, + "aca": _2, + "acct": _2, + "avocat": _2, + "bar": _2, + "cpa": _2, + "eng": _2, + "jur": _2, + "law": _2, + "med": _2, + "recht": _2, + "12chars": _3, + "cloudns": _3, + "dnstrace": [0, { + "bci": _3 + }], + "barsy": _3, + "ngrok": _3 + }], + "ps": [1, { + "edu": _2, + "gov": _2, + "sec": _2, + "plo": _2, + "com": _2, + "org": _2, + "net": _2 + }], + "pt": [1, { + "net": _2, + "gov": _2, + "org": _2, + "edu": _2, + "int": _2, + "publ": _2, + "com": _2, + "nome": _2, + "blogspot": _3, + "123paginaweb": _3 + }], + "pw": [1, { + "co": _2, + "ne": _2, + "or": _2, + "ed": _2, + "go": _2, + "belau": _2, + "cloudns": _3, + "x443": _3 + }], + "py": [1, { + "com": _2, + "coop": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "net": _2, + "org": _2 + }], + "qa": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "mil": _2, + "name": _2, + "net": _2, + "org": _2, + "sch": _2, + "blogspot": _3 + }], + "re": [1, { + "asso": _2, + "com": _2, + "nom": _2, + "blogspot": _3 + }], + "ro": [1, { + "arts": _2, + "com": _2, + "firm": _2, + "info": _2, + "nom": _2, + "nt": _2, + "org": _2, + "rec": _2, + "store": _2, + "tm": _2, + "www": _2, + "co": _3, + "shop": _3, + "blogspot": _3, + "barsy": _3 + }], + "rs": [1, { + "ac": _2, + "co": _2, + "edu": _2, + "gov": _2, + "in": _2, + "org": _2, + "brendly": [0, { + "shop": _3 + }], + "blogspot": _3, + "ua": _3, + "ox": _3 + }], + "ru": [1, { + "ac": _3, + "edu": _3, + "gov": _3, + "int": _3, + "mil": _3, + "test": _3, + "eurodir": _3, + "adygeya": _3, + "bashkiria": _3, + "bir": _3, + "cbg": _3, + "com": _3, + "dagestan": _3, + "grozny": _3, + "kalmykia": _3, + "kustanai": _3, + "marine": _3, + "mordovia": _3, + "msk": _3, + "mytis": _3, + "nalchik": _3, + "nov": _3, + "pyatigorsk": _3, + "spb": _3, + "vladikavkaz": _3, + "vladimir": _3, + "blogspot": _3, + "na4u": _3, + "mircloud": _3, + "regruhosting": _42, + "myjino": [2, { + "hosting": _5, + "landing": _5, + "spectrum": _5, + "vps": _5 + }], + "cldmail": [0, { + "hb": _3 + }], + "mcdir": [2, { + "vps": _3 + }], + "mcpre": _3, + "net": _3, + "org": _3, + "pp": _3, + "123sait": _3, + "lk3": _3, + "ras": _3 + }], + "rw": [1, { + "ac": _2, + "co": _2, + "coop": _2, + "gov": _2, + "mil": _2, + "net": _2, + "org": _2 + }], + "sa": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "med": _2, + "pub": _2, + "edu": _2, + "sch": _2 + }], + "sb": _4, + "sc": _4, + "sd": [1, { + "com": _2, + "net": _2, + "org": _2, + "edu": _2, + "med": _2, + "tv": _2, + "gov": _2, + "info": _2 + }], + "se": [1, { + "a": _2, + "ac": _2, + "b": _2, + "bd": _2, + "brand": _2, + "c": _2, + "d": _2, + "e": _2, + "f": _2, + "fh": _2, + "fhsk": _2, + "fhv": _2, + "g": _2, + "h": _2, + "i": _2, + "k": _2, + "komforb": _2, + "kommunalforbund": _2, + "komvux": _2, + "l": _2, + "lanbib": _2, + "m": _2, + "n": _2, + "naturbruksgymn": _2, + "o": _2, + "org": _2, + "p": _2, + "parti": _2, + "pp": _2, + "press": _2, + "r": _2, + "s": _2, + "t": _2, + "tm": _2, + "u": _2, + "w": _2, + "x": _2, + "y": _2, + "z": _2, + "com": _3, + "blogspot": _3, + "conf": _3, + "iopsys": _3, + "123minsida": _3, + "itcouldbewor": _3, + "myspreadshop": _3, + "paba": [0, { + "su": _3 + }] + }], + "sg": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "edu": _2, + "per": _2, + "blogspot": _3, + "enscaled": _3 + }], + "sh": [1, { + "com": _2, + "net": _2, + "gov": _2, + "org": _2, + "mil": _2, + "bip": _3, + "hashbang": _3, + "platform": [0, { + "ent": _3, + "eu": _3, + "us": _3 + }], + "now": _3, + "vxl": _3, + "wedeploy": _3 + }], + "si": [1, { + "f5": _3, + "gitapp": _3, + "gitpage": _3, + "blogspot": _3 + }], + "sj": _2, + "sk": _7, + "sl": _4, + "sm": _2, + "sn": [1, { + "art": _2, + "com": _2, + "edu": _2, + "gouv": _2, + "org": _2, + "perso": _2, + "univ": _2, + "blogspot": _3 + }], + "so": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "me": _2, + "net": _2, + "org": _2, + "sch": _3, + "surveys": _3 + }], + "sr": _2, + "ss": [1, { + "biz": _2, + "com": _2, + "edu": _2, + "gov": _2, + "me": _2, + "net": _2, + "org": _2, + "sch": _2 + }], + "st": [1, { + "co": _2, + "com": _2, + "consulado": _2, + "edu": _2, + "embaixada": _2, + "mil": _2, + "net": _2, + "org": _2, + "principe": _2, + "saotome": _2, + "store": _2, + "kirara": _3, + "noho": _3 + }], + "su": [1, { + "abkhazia": _3, + "adygeya": _3, + "aktyubinsk": _3, + "arkhangelsk": _3, + "armenia": _3, + "ashgabad": _3, + "azerbaijan": _3, + "balashov": _3, + "bashkiria": _3, + "bryansk": _3, + "bukhara": _3, + "chimkent": _3, + "dagestan": _3, + "east-kazakhstan": _3, + "exnet": _3, + "georgia": _3, + "grozny": _3, + "ivanovo": _3, + "jambyl": _3, + "kalmykia": _3, + "kaluga": _3, + "karacol": _3, + "karaganda": _3, + "karelia": _3, + "khakassia": _3, + "krasnodar": _3, + "kurgan": _3, + "kustanai": _3, + "lenug": _3, + "mangyshlak": _3, + "mordovia": _3, + "msk": _3, + "murmansk": _3, + "nalchik": _3, + "navoi": _3, + "north-kazakhstan": _3, + "nov": _3, + "obninsk": _3, + "penza": _3, + "pokrovsk": _3, + "sochi": _3, + "spb": _3, + "tashkent": _3, + "termez": _3, + "togliatti": _3, + "troitsk": _3, + "tselinograd": _3, + "tula": _3, + "tuva": _3, + "vladikavkaz": _3, + "vladimir": _3, + "vologda": _3 + }], + "sv": [1, { + "com": _2, + "edu": _2, + "gob": _2, + "org": _2, + "red": _2 + }], + "sx": _8, + "sy": _47, + "sz": [1, { + "co": _2, + "ac": _2, + "org": _2 + }], + "tc": [1, { + "ch": _3, + "me": _3, + "we": _3 + }], + "td": _7, + "tel": _2, + "tf": [1, { + "sch": _3 + }], + "tg": _2, + "th": [1, { + "ac": _2, + "co": _2, + "go": _2, + "in": _2, + "mi": _2, + "net": _2, + "or": _2, + "online": _3, + "shop": _3 + }], + "tj": [1, { + "ac": _2, + "biz": _2, + "co": _2, + "com": _2, + "edu": _2, + "go": _2, + "gov": _2, + "int": _2, + "mil": _2, + "name": _2, + "net": _2, + "nic": _2, + "org": _2, + "test": _2, + "web": _2 + }], + "tk": _2, + "tl": _8, + "tm": [1, { + "com": _2, + "co": _2, + "org": _2, + "net": _2, + "nom": _2, + "gov": _2, + "mil": _2, + "edu": _2 + }], + "tn": [1, { + "com": _2, + "ens": _2, + "fin": _2, + "gov": _2, + "ind": _2, + "info": _2, + "intl": _2, + "mincom": _2, + "nat": _2, + "net": _2, + "org": _2, + "perso": _2, + "tourism": _2, + "orangecloud": _3 + }], + "to": [1, { + "611": _3, + "com": _2, + "gov": _2, + "net": _2, + "org": _2, + "edu": _2, + "mil": _2, + "oya": _3, + "rdv": _3, + "x0": _3, + "vpnplus": _3, + "quickconnect": _21, + "nyan": _3 + }], + "tr": [1, { + "av": _2, + "bbs": _2, + "bel": _2, + "biz": _2, + "com": _7, + "dr": _2, + "edu": _2, + "gen": _2, + "gov": _2, + "info": _2, + "mil": _2, + "k12": _2, + "kep": _2, + "name": _2, + "net": _2, + "org": _2, + "pol": _2, + "tel": _2, + "tsk": _2, + "tv": _2, + "web": _2, + "nc": _8 + }], + "tt": [1, { + "co": _2, + "com": _2, + "org": _2, + "net": _2, + "biz": _2, + "info": _2, + "pro": _2, + "int": _2, + "coop": _2, + "jobs": _2, + "mobi": _2, + "travel": _2, + "museum": _2, + "aero": _2, + "name": _2, + "gov": _2, + "edu": _2 + }], + "tv": [1, { + "dyndns": _3, + "better-than": _3, + "on-the-web": _3, + "worse-than": _3, + "from": _3, + "sakura": _3 + }], + "tw": [1, { + "edu": _2, + "gov": _2, + "mil": _2, + "com": [1, { + "mymailer": _3 + }], + "net": _2, + "org": _2, + "idv": _2, + "game": _2, + "ebiz": _2, + "club": _2, + "xn--zf0ao64a": _2, + "網路": _2, + "xn--uc0atv": _2, + "組織": _2, + "xn--czrw28b": _2, + "商業": _2, + "url": _3, + "blogspot": _3 + }], + "tz": [1, { + "ac": _2, + "co": _2, + "go": _2, + "hotel": _2, + "info": _2, + "me": _2, + "mil": _2, + "mobi": _2, + "ne": _2, + "or": _2, + "sc": _2, + "tv": _2 + }], + "ua": [1, { + "com": _2, + "edu": _2, + "gov": _2, + "in": _2, + "net": _2, + "org": _2, + "cherkassy": _2, + "cherkasy": _2, + "chernigov": _2, + "chernihiv": _2, + "chernivtsi": _2, + "chernovtsy": _2, + "ck": _2, + "cn": _2, + "cr": _2, + "crimea": _2, + "cv": _2, + "dn": _2, + "dnepropetrovsk": _2, + "dnipropetrovsk": _2, + "donetsk": _2, + "dp": _2, + "if": _2, + "ivano-frankivsk": _2, + "kh": _2, + "kharkiv": _2, + "kharkov": _2, + "kherson": _2, + "khmelnitskiy": _2, + "khmelnytskyi": _2, + "kiev": _2, + "kirovograd": _2, + "km": _2, + "kr": _2, + "kropyvnytskyi": _2, + "krym": _2, + "ks": _2, + "kv": _2, + "kyiv": _2, + "lg": _2, + "lt": _2, + "lugansk": _2, + "luhansk": _2, + "lutsk": _2, + "lv": _2, + "lviv": _2, + "mk": _2, + "mykolaiv": _2, + "nikolaev": _2, + "od": _2, + "odesa": _2, + "odessa": _2, + "pl": _2, + "poltava": _2, + "rivne": _2, + "rovno": _2, + "rv": _2, + "sb": _2, + "sebastopol": _2, + "sevastopol": _2, + "sm": _2, + "sumy": _2, + "te": _2, + "ternopil": _2, + "uz": _2, + "uzhgorod": _2, + "uzhhorod": _2, + "vinnica": _2, + "vinnytsia": _2, + "vn": _2, + "volyn": _2, + "yalta": _2, + "zakarpattia": _2, + "zaporizhzhe": _2, + "zaporizhzhia": _2, + "zhitomir": _2, + "zhytomyr": _2, + "zp": _2, + "zt": _2, + "cc": _3, + "inf": _3, + "ltd": _3, + "cx": _3, + "ie": _3, + "biz": _3, + "co": _3, + "pp": _3, + "v": _3 + }], + "ug": [1, { + "co": _2, + "or": _2, + "ac": _2, + "sc": _2, + "go": _2, + "ne": _2, + "com": _2, + "org": _2, + "blogspot": _3 + }], + "uk": [1, { + "ac": _2, + "co": [1, { + "bytemark": [0, { + "dh": _3, + "vm": _3 + }], + "blogspot": _3, + "layershift": _41, + "barsy": _3, + "barsyonline": _3, + "retrosnub": _46, + "nh-serv": _3, + "no-ip": _3, + "wellbeingzone": _3, + "adimo": _3, + "myspreadshop": _3 + }], + "gov": [1, { + "campaign": _3, + "service": _3, + "api": _3 + }], + "ltd": _2, + "me": _2, + "net": _2, + "nhs": _2, + "org": [1, { + "glug": _3, + "lug": _3, + "lugs": _3, + "affinitylottery": _3, + "raffleentry": _3, + "weeklylottery": _3 + }], + "plc": _2, + "police": _2, + "sch": _13, + "conn": _3, + "copro": _3, + "hosp": _3, + "independent-commission": _3, + "independent-inquest": _3, + "independent-inquiry": _3, + "independent-panel": _3, + "independent-review": _3, + "public-inquiry": _3, + "royal-commission": _3, + "pymnt": _3, + "barsy": _3 + }], + "us": [1, { + "dni": _2, + "fed": _2, + "isa": _2, + "kids": _2, + "nsn": _2, + "ak": _56, + "al": _56, + "ar": _56, + "as": _56, + "az": _56, + "ca": _56, + "co": _56, + "ct": _56, + "dc": _56, + "de": [1, { + "cc": _2, + "lib": _3 + }], + "fl": _56, + "ga": _56, + "gu": _56, + "hi": _57, + "ia": _56, + "id": _56, + "il": _56, + "in": _56, + "ks": _56, + "ky": _56, + "la": _56, + "ma": [1, { + "k12": [1, { + "pvt": _2, + "chtr": _2, + "paroch": _2 + }], + "cc": _2, + "lib": _2 + }], + "md": _56, + "me": _56, + "mi": [1, { + "k12": _2, + "cc": _2, + "lib": _2, + "ann-arbor": _2, + "cog": _2, + "dst": _2, + "eaton": _2, + "gen": _2, + "mus": _2, + "tec": _2, + "washtenaw": _2 + }], + "mn": _56, + "mo": _56, + "ms": _56, + "mt": _56, + "nc": _56, + "nd": _57, + "ne": _56, + "nh": _56, + "nj": _56, + "nm": _56, + "nv": _56, + "ny": _56, + "oh": _56, + "ok": _56, + "or": _56, + "pa": _56, + "pr": _56, + "ri": _57, + "sc": _56, + "sd": _57, + "tn": _56, + "tx": _56, + "ut": _56, + "vi": _56, + "vt": _56, + "va": _56, + "wa": _56, + "wi": _56, + "wv": [1, { + "cc": _2 + }], + "wy": _56, + "graphox": _3, + "cloudns": _3, + "drud": _3, + "is-by": _3, + "land-4-sale": _3, + "stuff-4-sale": _3, + "enscaled": [0, { + "phx": _3 + }], + "mircloud": _3, + "freeddns": _3, + "golffan": _3, + "noip": _3, + "pointto": _3, + "platterp": _3, + "servername": _3 + }], + "uy": [1, { + "com": _7, + "edu": _2, + "gub": _2, + "mil": _2, + "net": _2, + "org": _2 + }], + "uz": [1, { + "co": _2, + "com": _2, + "net": _2, + "org": _2 + }], + "va": _2, + "vc": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "mil": _2, + "edu": _2, + "gv": [2, { + "d": _3 + }], + "0e": _3 + }], + "ve": [1, { + "arts": _2, + "bib": _2, + "co": _2, + "com": _2, + "e12": _2, + "edu": _2, + "firm": _2, + "gob": _2, + "gov": _2, + "info": _2, + "int": _2, + "mil": _2, + "net": _2, + "nom": _2, + "org": _2, + "rar": _2, + "rec": _2, + "store": _2, + "tec": _2, + "web": _2 + }], + "vg": [1, { + "at": _3 + }], + "vi": [1, { + "co": _2, + "com": _2, + "k12": _2, + "net": _2, + "org": _2 + }], + "vn": [1, { + "ac": _2, + "ai": _2, + "biz": _2, + "com": _2, + "edu": _2, + "gov": _2, + "health": _2, + "id": _2, + "info": _2, + "int": _2, + "io": _2, + "name": _2, + "net": _2, + "org": _2, + "pro": _2, + "angiang": _2, + "bacgiang": _2, + "backan": _2, + "baclieu": _2, + "bacninh": _2, + "baria-vungtau": _2, + "bentre": _2, + "binhdinh": _2, + "binhduong": _2, + "binhphuoc": _2, + "binhthuan": _2, + "camau": _2, + "cantho": _2, + "caobang": _2, + "daklak": _2, + "daknong": _2, + "danang": _2, + "dienbien": _2, + "dongnai": _2, + "dongthap": _2, + "gialai": _2, + "hagiang": _2, + "haiduong": _2, + "haiphong": _2, + "hanam": _2, + "hanoi": _2, + "hatinh": _2, + "haugiang": _2, + "hoabinh": _2, + "hungyen": _2, + "khanhhoa": _2, + "kiengiang": _2, + "kontum": _2, + "laichau": _2, + "lamdong": _2, + "langson": _2, + "laocai": _2, + "longan": _2, + "namdinh": _2, + "nghean": _2, + "ninhbinh": _2, + "ninhthuan": _2, + "phutho": _2, + "phuyen": _2, + "quangbinh": _2, + "quangnam": _2, + "quangngai": _2, + "quangninh": _2, + "quangtri": _2, + "soctrang": _2, + "sonla": _2, + "tayninh": _2, + "thaibinh": _2, + "thainguyen": _2, + "thanhhoa": _2, + "thanhphohochiminh": _2, + "thuathienhue": _2, + "tiengiang": _2, + "travinh": _2, + "tuyenquang": _2, + "vinhlong": _2, + "vinhphuc": _2, + "yenbai": _2, + "blogspot": _3 + }], + "vu": [1, { + "com": _2, + "edu": _2, + "net": _2, + "org": _2, + "cn": _3, + "blog": _3, + "dev": _3, + "me": _3 + }], + "wf": [1, { + "biz": _3, + "sch": _3 + }], + "ws": [1, { + "com": _2, + "net": _2, + "org": _2, + "gov": _2, + "edu": _2, + "advisor": _5, + "cloud66": _3, + "dyndns": _3, + "mypets": _3 + }], + "yt": [1, { + "org": _3 + }], + "xn--mgbaam7a8h": _2, + "امارات": _2, + "xn--y9a3aq": _2, + "Õ°Õ¡Õµ": _2, + "xn--54b7fta0cc": _2, + "বাংলা": _2, + "xn--90ae": _2, + "бг": _2, + "xn--mgbcpq6gpa1a": _2, + "البحرين": _2, + "xn--90ais": _2, + "бел": _2, + "xn--fiqs8s": _2, + "中国": _2, + "xn--fiqz9s": _2, + "中國": _2, + "xn--lgbbat1ad8j": _2, + "الجزائر": _2, + "xn--wgbh1c": _2, + "مصر": _2, + "xn--e1a4c": _2, + "ею": _2, + "xn--qxa6a": _2, + "ευ": _2, + "xn--mgbah1a3hjkrd": _2, + "موريتانيا": _2, + "xn--node": _2, + "გე": _2, + "xn--qxam": _2, + "ελ": _2, + "xn--j6w193g": [1, { + "xn--55qx5d": _2, + "xn--wcvs22d": _2, + "xn--mxtq1m": _2, + "xn--gmqw5a": _2, + "xn--od0alg": _2, + "xn--uc0atv": _2 + }], + "香港": [1, { + "å…¬å¸": _2, + "教育": _2, + "政府": _2, + "個人": _2, + "網絡": _2, + "組織": _2 + }], + "xn--2scrj9c": _2, + "ಭಾರತ": _2, + "xn--3hcrj9c": _2, + "ଭାରତ": _2, + "xn--45br5cyl": _2, + "ভাৰত": _2, + "xn--h2breg3eve": _2, + "भारतमà¥": _2, + "xn--h2brj9c8c": _2, + "भारोत": _2, + "xn--mgbgu82a": _2, + "ڀارت": _2, + "xn--rvc1e0am3e": _2, + "ഭാരതം": _2, + "xn--h2brj9c": _2, + "भारत": _2, + "xn--mgbbh1a": _2, + "بارت": _2, + "xn--mgbbh1a71e": _2, + "بھارت": _2, + "xn--fpcrj9c3d": _2, + "భారతà±": _2, + "xn--gecrj9c": _2, + "ભારત": _2, + "xn--s9brj9c": _2, + "ਭਾਰਤ": _2, + "xn--45brj9c": _2, + "ভারত": _2, + "xn--xkc2dl3a5ee0h": _2, + "இநà¯à®¤à®¿à®¯à®¾": _2, + "xn--mgba3a4f16a": _2, + "ایران": _2, + "xn--mgba3a4fra": _2, + "ايران": _2, + "xn--mgbtx2b": _2, + "عراق": _2, + "xn--mgbayh7gpa": _2, + "الاردن": _2, + "xn--3e0b707e": _2, + "한국": _2, + "xn--80ao21a": _2, + "қаз": _2, + "xn--q7ce6a": _2, + "ລາວ": _2, + "xn--fzc2c9e2c": _2, + "ලංකà·": _2, + "xn--xkc2al3hye2a": _2, + "இலஙà¯à®•ை": _2, + "xn--mgbc0a9azcg": _2, + "المغرب": _2, + "xn--d1alf": _2, + "мкд": _2, + "xn--l1acc": _2, + "мон": _2, + "xn--mix891f": _2, + "澳門": _2, + "xn--mix082f": _2, + "澳门": _2, + "xn--mgbx4cd0ab": _2, + "مليسيا": _2, + "xn--mgb9awbf": _2, + "عمان": _2, + "xn--mgbai9azgqp6j": _2, + "پاکستان": _2, + "xn--mgbai9a5eva00b": _2, + "پاكستان": _2, + "xn--ygbi2ammx": _2, + "Ùلسطين": _2, + "xn--90a3ac": [1, { + "xn--o1ac": _2, + "xn--c1avg": _2, + "xn--90azh": _2, + "xn--d1at": _2, + "xn--o1ach": _2, + "xn--80au": _2 + }], + "Ñрб": [1, { + "пр": _2, + "орг": _2, + "обр": _2, + "од": _2, + "упр": _2, + "ак": _2 + }], + "xn--p1ai": _2, + "рф": _2, + "xn--wgbl6a": _2, + "قطر": _2, + "xn--mgberp4a5d4ar": _2, + "السعودية": _2, + "xn--mgberp4a5d4a87g": _2, + "السعودیة": _2, + "xn--mgbqly7c0a67fbc": _2, + "السعودیۃ": _2, + "xn--mgbqly7cvafr": _2, + "السعوديه": _2, + "xn--mgbpl2fh": _2, + "سودان": _2, + "xn--yfro4i67o": _2, + "新加å¡": _2, + "xn--clchc0ea0b2g2a9gcd": _2, + "சிஙà¯à®•பà¯à®ªà¯‚à®°à¯": _2, + "xn--ogbpf8fl": _2, + "سورية": _2, + "xn--mgbtf8fl": _2, + "سوريا": _2, + "xn--o3cw4h": [1, { + "xn--12c1fe0br": _2, + "xn--12co0c3b4eva": _2, + "xn--h3cuzk1di": _2, + "xn--o3cyx2a": _2, + "xn--m3ch0j3a": _2, + "xn--12cfi8ixb8l": _2 + }], + "ไทย": [1, { + "ศึà¸à¸©à¸²": _2, + "ธุรà¸à¸´à¸ˆ": _2, + "รัà¸à¸šà¸²à¸¥": _2, + "ทหาร": _2, + "เน็ต": _2, + "องค์à¸à¸£": _2 + }], + "xn--pgbs0dh": _2, + "تونس": _2, + "xn--kpry57d": _2, + "å°ç£": _2, + "xn--kprw13d": _2, + "å°æ¹¾": _2, + "xn--nnx388a": _2, + "臺ç£": _2, + "xn--j1amh": _2, + "укр": _2, + "xn--mgb2ddes": _2, + "اليمن": _2, + "xxx": _2, + "ye": _47, + "za": [0, { + "ac": _2, + "agric": _2, + "alt": _2, + "co": _7, + "edu": _2, + "gov": _2, + "grondar": _2, + "law": _2, + "mil": _2, + "net": _2, + "ngo": _2, + "nic": _2, + "nis": _2, + "nom": _2, + "org": _2, + "school": _2, + "tm": _2, + "web": _2 + }], + "zm": [1, { + "ac": _2, + "biz": _2, + "co": _2, + "com": _2, + "edu": _2, + "gov": _2, + "info": _2, + "mil": _2, + "net": _2, + "org": _2, + "sch": _2 + }], + "zw": [1, { + "ac": _2, + "co": _2, + "gov": _2, + "mil": _2, + "org": _2 + }], + "aaa": _2, + "aarp": _2, + "abb": _2, + "abbott": _2, + "abbvie": _2, + "abc": _2, + "able": _2, + "abogado": _2, + "abudhabi": _2, + "academy": [1, { + "official": _3 + }], + "accenture": _2, + "accountant": _2, + "accountants": _2, + "aco": _2, + "actor": _2, + "ads": _2, + "adult": _2, + "aeg": _2, + "aetna": _2, + "afl": _2, + "africa": _2, + "agakhan": _2, + "agency": _2, + "aig": _2, + "airbus": _2, + "airforce": _2, + "airtel": _2, + "akdn": _2, + "alibaba": _2, + "alipay": _2, + "allfinanz": _2, + "allstate": _2, + "ally": _2, + "alsace": _2, + "alstom": _2, + "amazon": _2, + "americanexpress": _2, + "americanfamily": _2, + "amex": _2, + "amfam": _2, + "amica": _2, + "amsterdam": _2, + "analytics": _2, + "android": _2, + "anquan": _2, + "anz": _2, + "aol": _2, + "apartments": _2, + "app": [1, { + "adaptable": _3, + "beget": _5, + "clerk": _3, + "clerkstage": _3, + "wnext": _3, + "cyclic": _3, + "platform0": _3, + "deta": _3, + "ondigitalocean": _3, + "easypanel": _3, + "encr": _3, + "edgecompute": _3, + "fireweb": _3, + "onflashdrive": _3, + "flutterflow": _3, + "framer": _3, + "run": _5, + "web": _3, + "hasura": _3, + "loginline": _3, + "messerli": _3, + "netlify": _3, + "ngrok": _3, + "ngrok-free": _3, + "developer": _5, + "noop": _3, + "northflank": _5, + "upsun": _5, + "replit": _6, + "snowflake": [2, { + "privatelink": _3 + }], + "streamlit": _3, + "storipress": _3, + "telebit": _3, + "typedream": _3, + "vercel": _3, + "bookonline": _3 + }], + "apple": _2, + "aquarelle": _2, + "arab": _2, + "aramco": _2, + "archi": _2, + "army": _2, + "art": _2, + "arte": _2, + "asda": _2, + "associates": _2, + "athleta": _2, + "attorney": _2, + "auction": _2, + "audi": _2, + "audible": _2, + "audio": _2, + "auspost": _2, + "author": _2, + "auto": _2, + "autos": _2, + "avianca": _2, + "aws": [1, { + "sagemaker": [0, { + "af-south-1": _9, + "ap-east-1": _9, + "ap-northeast-1": _9, + "ap-northeast-2": _9, + "ap-northeast-3": _9, + "ap-south-1": _9, + "ap-south-2": _10, + "ap-southeast-1": _9, + "ap-southeast-2": _9, + "ap-southeast-3": _9, + "ap-southeast-4": _10, + "ca-central-1": _11, + "ca-west-1": [0, { + "notebook": _3, + "notebook-fips": _3 + }], + "eu-central-1": _9, + "eu-central-2": _10, + "eu-north-1": _9, + "eu-south-1": _9, + "eu-south-2": _10, + "eu-west-1": _9, + "eu-west-2": _9, + "eu-west-3": _9, + "il-central-1": _9, + "me-central-1": _9, + "me-south-1": _9, + "sa-east-1": _9, + "us-east-1": _11, + "us-east-2": _11, + "us-gov-east-1": _12, + "us-gov-west-1": _12, + "us-west-1": _9, + "us-west-2": _11 + }], + "repost": [0, { + "private": _5 + }] + }], + "axa": _2, + "azure": _2, + "baby": _2, + "baidu": _2, + "banamex": _2, + "band": _2, + "bank": _2, + "bar": _2, + "barcelona": _2, + "barclaycard": _2, + "barclays": _2, + "barefoot": _2, + "bargains": _2, + "baseball": _2, + "basketball": [1, { + "aus": _3, + "nz": _3 + }], + "bauhaus": _2, + "bayern": _2, + "bbc": _2, + "bbt": _2, + "bbva": _2, + "bcg": _2, + "bcn": _2, + "beats": _2, + "beauty": _2, + "beer": _2, + "bentley": _2, + "berlin": _2, + "best": _2, + "bestbuy": _2, + "bet": _2, + "bharti": _2, + "bible": _2, + "bid": _2, + "bike": _2, + "bing": _2, + "bingo": _2, + "bio": _2, + "black": _2, + "blackfriday": _2, + "blockbuster": _2, + "blog": _2, + "bloomberg": _2, + "blue": _2, + "bms": _2, + "bmw": _2, + "bnpparibas": _2, + "boats": _2, + "boehringer": _2, + "bofa": _2, + "bom": _2, + "bond": _2, + "boo": _2, + "book": _2, + "booking": _2, + "bosch": _2, + "bostik": _2, + "boston": _2, + "bot": _2, + "boutique": _2, + "box": _2, + "bradesco": _2, + "bridgestone": _2, + "broadway": _2, + "broker": _2, + "brother": _2, + "brussels": _2, + "build": _2, + "builders": [1, { + "cloudsite": _3 + }], + "business": _15, + "buy": _2, + "buzz": _2, + "bzh": _2, + "cab": _2, + "cafe": _2, + "cal": _2, + "call": _2, + "calvinklein": _2, + "cam": _2, + "camera": _2, + "camp": _2, + "canon": _2, + "capetown": _2, + "capital": _2, + "capitalone": _2, + "car": _2, + "caravan": _2, + "cards": _2, + "care": _2, + "career": _2, + "careers": _2, + "cars": _2, + "casa": [1, { + "nabu": [0, { + "ui": _3 + }] + }], + "case": _2, + "cash": _2, + "casino": _2, + "catering": _2, + "catholic": _2, + "cba": _2, + "cbn": _2, + "cbre": _2, + "center": _2, + "ceo": _2, + "cern": _2, + "cfa": _2, + "cfd": _2, + "chanel": _2, + "channel": _2, + "charity": _2, + "chase": _2, + "chat": _2, + "cheap": _2, + "chintai": _2, + "christmas": _2, + "chrome": _2, + "church": _2, + "cipriani": _2, + "circle": _2, + "cisco": _2, + "citadel": _2, + "citi": _2, + "citic": _2, + "city": _2, + "claims": _2, + "cleaning": _2, + "click": _2, + "clinic": _2, + "clinique": _2, + "clothing": _2, + "cloud": [1, { + "banzai": _5, + "cyclic": _3, + "elementor": _3, + "encoway": [0, { + "eu": _3 + }], + "statics": _5, + "ravendb": _3, + "axarnet": [0, { + "es-1": _3 + }], + "diadem": _3, + "jelastic": [0, { + "vip": _3 + }], + "jele": _3, + "jenv-aruba": [0, { + "aruba": [0, { + "eur": [0, { + "it1": _3 + }] + }], + "it1": _3 + }], + "keliweb": [2, { + "cs": _3 + }], + "oxa": [2, { + "tn": _3, + "uk": _3 + }], + "primetel": [2, { + "uk": _3 + }], + "reclaim": [0, { + "ca": _3, + "uk": _3, + "us": _3 + }], + "trendhosting": [0, { + "ch": _3, + "de": _3 + }], + "jotelulu": _3, + "kuleuven": _3, + "linkyard": _3, + "magentosite": _5, + "perspecta": _3, + "vapor": _3, + "on-rancher": _5, + "scw": [0, { + "baremetal": [0, { + "fr-par-1": _3, + "fr-par-2": _3, + "nl-ams-1": _3 + }], + "fr-par": [0, { + "cockpit": _3, + "fnc": [2, { + "functions": _3 + }], + "k8s": _16, + "s3": _3, + "s3-website": _3, + "whm": _3 + }], + "instances": [0, { + "priv": _3, + "pub": _3 + }], + "k8s": _3, + "nl-ams": [0, { + "cockpit": _3, + "k8s": _16, + "s3": _3, + "s3-website": _3, + "whm": _3 + }], + "pl-waw": [0, { + "cockpit": _3, + "k8s": _16, + "s3": _3, + "s3-website": _3 + }], + "scalebook": _3, + "smartlabeling": _3 + }], + "onstackit": [0, { + "runs": _3 + }], + "sensiosite": _5, + "trafficplex": _3, + "urown": _3, + "voorloper": _3, + "zap": _3 + }], + "club": [1, { + "cloudns": _3, + "jele": _3, + "barsy": _3 + }], + "clubmed": _2, + "coach": _2, + "codes": [1, { + "owo": _5 + }], + "coffee": _2, + "college": _2, + "cologne": _2, + "commbank": _2, + "community": [1, { + "nog": _3, + "ravendb": _3, + "myforum": _3 + }], + "company": _2, + "compare": _2, + "computer": _2, + "comsec": _2, + "condos": _2, + "construction": _2, + "consulting": _2, + "contact": _2, + "contractors": _2, + "cooking": _2, + "cool": [1, { + "elementor": _3, + "de": _3 + }], + "corsica": _2, + "country": _2, + "coupon": _2, + "coupons": _2, + "courses": _2, + "cpa": _2, + "credit": _2, + "creditcard": _2, + "creditunion": _2, + "cricket": _2, + "crown": _2, + "crs": _2, + "cruise": _2, + "cruises": _2, + "cuisinella": _2, + "cymru": _2, + "cyou": _2, + "dabur": _2, + "dad": _2, + "dance": _2, + "data": _2, + "date": _2, + "dating": _2, + "datsun": _2, + "day": _2, + "dclk": _2, + "dds": _2, + "deal": _2, + "dealer": _2, + "deals": _2, + "degree": _2, + "delivery": _2, + "dell": _2, + "deloitte": _2, + "delta": _2, + "democrat": _2, + "dental": _2, + "dentist": _2, + "desi": _2, + "design": [1, { + "bss": _3 + }], + "dev": [1, { + "12chars": _3, + "panel": _3, + "autocode": _3, + "lcl": _5, + "lclstage": _5, + "stg": _5, + "stgstage": _5, + "pages": _3, + "r2": _3, + "workers": _3, + "curv": _3, + "deno": _3, + "deno-staging": _3, + "deta": _3, + "fly": _3, + "githubpreview": _3, + "gateway": _5, + "iserv": _3, + "localcert": [0, { + "user": _5 + }], + "loginline": _3, + "mediatech": _3, + "modx": _3, + "ngrok": _3, + "ngrok-free": _3, + "platter-app": _3, + "replit": [2, { + "archer": _3, + "bones": _3, + "canary": _3, + "global": _3, + "hacker": _3, + "id": _3, + "janeway": _3, + "kim": _3, + "kira": _3, + "kirk": _3, + "odo": _3, + "paris": _3, + "picard": _3, + "pike": _3, + "prerelease": _3, + "reed": _3, + "riker": _3, + "sisko": _3, + "spock": _3, + "staging": _3, + "sulu": _3, + "tarpit": _3, + "teams": _3, + "tucker": _3, + "wesley": _3, + "worf": _3 + }], + "shiftcrypto": _3, + "vercel": _3, + "webhare": _5 + }], + "dhl": _2, + "diamonds": _2, + "diet": _2, + "digital": [1, { + "cloudapps": [2, { + "london": _3 + }] + }], + "direct": _2, + "directory": _2, + "discount": _2, + "discover": _2, + "dish": _2, + "diy": _2, + "dnp": _2, + "docs": _2, + "doctor": _2, + "dog": _2, + "domains": _2, + "dot": _2, + "download": _2, + "drive": _2, + "dtv": _2, + "dubai": _2, + "dunlop": _2, + "dupont": _2, + "durban": _2, + "dvag": _2, + "dvr": _2, + "earth": [1, { + "dapps": [0, { + "*": _3, + "bzz": _5 + }] + }], + "eat": _2, + "eco": _2, + "edeka": _2, + "education": _15, + "email": [1, { + "crisp": [0, { + "on": _3 + }] + }], + "emerck": _2, + "energy": _2, + "engineer": _2, + "engineering": _2, + "enterprises": _2, + "epson": _2, + "equipment": _2, + "ericsson": _2, + "erni": _2, + "esq": _2, + "estate": [1, { + "compute": _5 + }], + "eurovision": _2, + "eus": [1, { + "party": _43 + }], + "events": [1, { + "koobin": _3, + "co": _3 + }], + "exchange": _2, + "expert": _2, + "exposed": _2, + "express": _2, + "extraspace": _2, + "fage": _2, + "fail": _2, + "fairwinds": _2, + "faith": _44, + "family": _2, + "fan": _2, + "fans": _2, + "farm": [1, { + "storj": _3 + }], + "farmers": _2, + "fashion": _2, + "fast": _2, + "fedex": _2, + "feedback": _2, + "ferrari": _2, + "ferrero": _2, + "fidelity": _2, + "fido": _2, + "film": _2, + "final": _2, + "finance": _2, + "financial": _15, + "fire": _2, + "firestone": _2, + "firmdale": _2, + "fish": _2, + "fishing": _2, + "fit": _2, + "fitness": _2, + "flickr": _2, + "flights": _2, + "flir": _2, + "florist": _2, + "flowers": _2, + "fly": _2, + "foo": _2, + "food": _2, + "football": _2, + "ford": _2, + "forex": _2, + "forsale": _2, + "forum": _2, + "foundation": _2, + "fox": _2, + "free": _2, + "fresenius": _2, + "frl": _2, + "frogans": _2, + "frontier": _2, + "ftr": _2, + "fujitsu": _2, + "fun": _2, + "fund": _2, + "furniture": _2, + "futbol": _2, + "fyi": _2, + "gal": _2, + "gallery": _2, + "gallo": _2, + "gallup": _2, + "game": _2, + "games": [1, { + "pley": _3 + }], + "gap": _2, + "garden": _2, + "gay": [1, { + "pages": _3 + }], + "gbiz": _2, + "gdn": [1, { + "cnpy": _3 + }], + "gea": _2, + "gent": _2, + "genting": _2, + "george": _2, + "ggee": _2, + "gift": _2, + "gifts": _2, + "gives": _2, + "giving": _2, + "glass": _2, + "gle": _2, + "global": _2, + "globo": _2, + "gmail": _2, + "gmbh": _2, + "gmo": _2, + "gmx": _2, + "godaddy": _2, + "gold": _2, + "goldpoint": _2, + "golf": _2, + "goo": _2, + "goodyear": _2, + "goog": [1, { + "cloud": _3, + "translate": _3, + "usercontent": _5 + }], + "google": _2, + "gop": _2, + "got": _2, + "grainger": _2, + "graphics": _2, + "gratis": _2, + "green": _2, + "gripe": _2, + "grocery": _2, + "group": [1, { + "discourse": _3 + }], + "gucci": _2, + "guge": _2, + "guide": _2, + "guitars": _2, + "guru": _2, + "hair": _2, + "hamburg": _2, + "hangout": _2, + "haus": _2, + "hbo": _2, + "hdfc": _2, + "hdfcbank": _2, + "health": [1, { + "hra": _3 + }], + "healthcare": _2, + "help": _2, + "helsinki": _2, + "here": _2, + "hermes": _2, + "hiphop": _2, + "hisamitsu": _2, + "hitachi": _2, + "hiv": _2, + "hkt": _2, + "hockey": _2, + "holdings": _2, + "holiday": _2, + "homedepot": _2, + "homegoods": _2, + "homes": _2, + "homesense": _2, + "honda": _2, + "horse": _2, + "hospital": _2, + "host": [1, { + "cloudaccess": _3, + "freesite": _3, + "easypanel": _3, + "fastvps": _3, + "myfast": _3, + "tempurl": _3, + "wpmudev": _3, + "jele": _3, + "mircloud": _3, + "pcloud": _3, + "half": _3 + }], + "hosting": [1, { + "opencraft": _3 + }], + "hot": _2, + "hotels": _2, + "hotmail": _2, + "house": _2, + "how": _2, + "hsbc": _2, + "hughes": _2, + "hyatt": _2, + "hyundai": _2, + "ibm": _2, + "icbc": _2, + "ice": _2, + "icu": _2, + "ieee": _2, + "ifm": _2, + "ikano": _2, + "imamat": _2, + "imdb": _2, + "immo": _2, + "immobilien": _2, + "inc": _2, + "industries": _2, + "infiniti": _2, + "ing": _2, + "ink": _2, + "institute": _2, + "insurance": _2, + "insure": _2, + "international": _2, + "intuit": _2, + "investments": _2, + "ipiranga": _2, + "irish": _2, + "ismaili": _2, + "ist": _2, + "istanbul": _2, + "itau": _2, + "itv": _2, + "jaguar": _2, + "java": _2, + "jcb": _2, + "jeep": _2, + "jetzt": _2, + "jewelry": _2, + "jio": _2, + "jll": _2, + "jmp": _2, + "jnj": _2, + "joburg": _2, + "jot": _2, + "joy": _2, + "jpmorgan": _2, + "jprs": _2, + "juegos": _2, + "juniper": _2, + "kaufen": _2, + "kddi": _2, + "kerryhotels": _2, + "kerrylogistics": _2, + "kerryproperties": _2, + "kfh": _2, + "kia": _2, + "kids": _2, + "kim": _2, + "kindle": _2, + "kitchen": _2, + "kiwi": _2, + "koeln": _2, + "komatsu": _2, + "kosher": _2, + "kpmg": _2, + "kpn": _2, + "krd": [1, { + "co": _3, + "edu": _3 + }], + "kred": _2, + "kuokgroup": _2, + "kyoto": _2, + "lacaixa": _2, + "lamborghini": _2, + "lamer": _2, + "lancaster": _2, + "land": [1, { + "static": [2, { + "dev": _3, + "sites": _3 + }] + }], + "landrover": _2, + "lanxess": _2, + "lasalle": _2, + "lat": _2, + "latino": _2, + "latrobe": _2, + "law": _2, + "lawyer": _2, + "lds": _2, + "lease": _2, + "leclerc": _2, + "lefrak": _2, + "legal": _2, + "lego": _2, + "lexus": _2, + "lgbt": _2, + "lidl": _2, + "life": _2, + "lifeinsurance": _2, + "lifestyle": _2, + "lighting": _2, + "like": _2, + "lilly": _2, + "limited": _2, + "limo": _2, + "lincoln": _2, + "link": [1, { + "cyon": _3, + "mypep": _3, + "dweb": _5 + }], + "lipsy": _2, + "live": [1, { + "aem": _3, + "hlx": _3, + "ewp": _5 + }], + "living": _2, + "llc": _2, + "llp": _2, + "loan": _2, + "loans": _2, + "locker": _2, + "locus": _2, + "lol": [1, { + "omg": _3 + }], + "london": _2, + "lotte": _2, + "lotto": _2, + "love": _2, + "lpl": _2, + "lplfinancial": _2, + "ltd": _2, + "ltda": _2, + "lundbeck": _2, + "luxe": _2, + "luxury": _2, + "madrid": _2, + "maif": _2, + "maison": _2, + "makeup": _2, + "man": _2, + "management": [1, { + "router": _3 + }], + "mango": _2, + "map": _2, + "market": _2, + "marketing": _2, + "markets": _2, + "marriott": _2, + "marshalls": _2, + "mattel": _2, + "mba": _2, + "mckinsey": _2, + "med": _2, + "media": _51, + "meet": _2, + "melbourne": _2, + "meme": _2, + "memorial": _2, + "men": _2, + "menu": _52, + "merckmsd": _2, + "miami": _2, + "microsoft": _2, + "mini": _2, + "mint": _2, + "mit": _2, + "mitsubishi": _2, + "mlb": _2, + "mls": _2, + "mma": _2, + "mobile": _2, + "moda": _2, + "moe": _2, + "moi": _2, + "mom": _2, + "monash": _2, + "money": _2, + "monster": _2, + "mormon": _2, + "mortgage": _2, + "moscow": _2, + "moto": _2, + "motorcycles": _2, + "mov": _2, + "movie": _2, + "msd": _2, + "mtn": _2, + "mtr": _2, + "music": _2, + "nab": _2, + "nagoya": _2, + "natura": _2, + "navy": _2, + "nba": _2, + "nec": _2, + "netbank": _2, + "netflix": _2, + "network": [1, { + "alces": _5, + "co": _3, + "arvo": _3, + "azimuth": _3, + "tlon": _3 + }], + "neustar": _2, + "new": _2, + "news": [1, { + "noticeable": _3 + }], + "next": _2, + "nextdirect": _2, + "nexus": _2, + "nfl": _2, + "ngo": _2, + "nhk": _2, + "nico": _2, + "nike": _2, + "nikon": _2, + "ninja": _2, + "nissan": _2, + "nissay": _2, + "nokia": _2, + "norton": _2, + "now": _2, + "nowruz": _2, + "nowtv": _2, + "nra": _2, + "nrw": _2, + "ntt": _2, + "nyc": _2, + "obi": _2, + "observer": _2, + "office": _2, + "okinawa": _2, + "olayan": _2, + "olayangroup": _2, + "ollo": _2, + "omega": _2, + "one": [1, { + "onred": [2, { + "staging": _3 + }], + "kin": _5, + "service": _3, + "homelink": _3 + }], + "ong": _2, + "onl": _2, + "online": [1, { + "eero": _3, + "eero-stage": _3, + "barsy": _3 + }], + "ooo": _2, + "open": _2, + "oracle": _2, + "orange": [1, { + "tech": _3 + }], + "organic": _2, + "origins": _2, + "osaka": _2, + "otsuka": _2, + "ott": _2, + "ovh": [1, { + "nerdpol": _3 + }], + "page": [1, { + "aem": _3, + "hlx": _3, + "hlx3": _3, + "translated": _3, + "codeberg": _3, + "pdns": _3, + "plesk": _3, + "prvcy": _3, + "rocky": _3, + "magnet": _3 + }], + "panasonic": _2, + "paris": _2, + "pars": _2, + "partners": _2, + "parts": _2, + "party": _44, + "pay": _2, + "pccw": _2, + "pet": _2, + "pfizer": _2, + "pharmacy": _2, + "phd": _2, + "philips": _2, + "phone": _2, + "photo": _2, + "photography": _2, + "photos": _51, + "physio": _2, + "pics": _2, + "pictet": _2, + "pictures": [1, { + "1337": _3 + }], + "pid": _2, + "pin": _2, + "ping": _2, + "pink": _2, + "pioneer": _2, + "pizza": [1, { + "ngrok": _3 + }], + "place": _15, + "play": _2, + "playstation": _2, + "plumbing": _2, + "plus": _2, + "pnc": _2, + "pohl": _2, + "poker": _2, + "politie": _2, + "porn": [1, { + "indie": _3 + }], + "pramerica": _2, + "praxi": _2, + "press": _2, + "prime": _2, + "prod": _2, + "productions": _2, + "prof": _2, + "progressive": _2, + "promo": _2, + "properties": _2, + "property": _2, + "protection": _2, + "pru": _2, + "prudential": _2, + "pub": [1, { + "id": _5, + "kin": _5, + "barsy": _3 + }], + "pwc": _2, + "qpon": _2, + "quebec": _2, + "quest": _2, + "racing": _2, + "radio": _2, + "read": _2, + "realestate": _2, + "realtor": _2, + "realty": _2, + "recipes": _2, + "red": _2, + "redstone": _2, + "redumbrella": _2, + "rehab": _2, + "reise": _2, + "reisen": _2, + "reit": _2, + "reliance": _2, + "ren": _2, + "rent": _2, + "rentals": _2, + "repair": _2, + "report": _2, + "republican": _2, + "rest": _2, + "restaurant": _2, + "review": _44, + "reviews": _2, + "rexroth": _2, + "rich": _2, + "richardli": _2, + "ricoh": _2, + "ril": _2, + "rio": _2, + "rip": [1, { + "clan": _3 + }], + "rocks": [1, { + "myddns": _3, + "stackit": _3, + "lima-city": _3, + "webspace": _3 + }], + "rodeo": _2, + "rogers": _2, + "room": _2, + "rsvp": _2, + "rugby": _2, + "ruhr": _2, + "run": [1, { + "hs": _3, + "development": _3, + "ravendb": _3, + "servers": _3, + "build": _5, + "code": _5, + "database": _5, + "migration": _5, + "onporter": _3, + "repl": _3, + "stackit": _3, + "wix": _3 + }], + "rwe": _2, + "ryukyu": _2, + "saarland": _2, + "safe": _2, + "safety": _2, + "sakura": _2, + "sale": _2, + "salon": _2, + "samsclub": _2, + "samsung": _2, + "sandvik": _2, + "sandvikcoromant": _2, + "sanofi": _2, + "sap": _2, + "sarl": _2, + "sas": _2, + "save": _2, + "saxo": _2, + "sbi": _2, + "sbs": _2, + "scb": _2, + "schaeffler": _2, + "schmidt": _2, + "scholarships": _2, + "school": _2, + "schule": _2, + "schwarz": _2, + "science": _44, + "scot": [1, { + "edu": _3, + "gov": [2, { + "service": _3 + }] + }], + "search": _2, + "seat": _2, + "secure": _2, + "security": _2, + "seek": _2, + "select": _2, + "sener": _2, + "services": [1, { + "loginline": _3 + }], + "seven": _2, + "sew": _2, + "sex": _2, + "sexy": _2, + "sfr": _2, + "shangrila": _2, + "sharp": _2, + "shaw": _2, + "shell": _2, + "shia": _2, + "shiksha": _2, + "shoes": _2, + "shop": [1, { + "base": _3, + "hoplix": _3, + "barsy": _3 + }], + "shopping": _2, + "shouji": _2, + "show": _2, + "silk": _2, + "sina": _2, + "singles": _2, + "site": [1, { + "canva": _17, + "cloudera": _5, + "convex": _3, + "cyon": _3, + "fnwk": _3, + "folionetwork": _3, + "fastvps": _3, + "jele": _3, + "lelux": _3, + "loginline": _3, + "barsy": _3, + "mintere": _3, + "omniwe": _3, + "opensocial": _3, + "platformsh": _5, + "tst": _5, + "byen": _3, + "srht": _3, + "novecore": _3 + }], + "ski": _2, + "skin": _2, + "sky": _2, + "skype": _2, + "sling": _2, + "smart": _2, + "smile": _2, + "sncf": _2, + "soccer": _2, + "social": _2, + "softbank": _2, + "software": _2, + "sohu": _2, + "solar": _2, + "solutions": [1, { + "diher": _5 + }], + "song": _2, + "sony": _2, + "soy": _2, + "spa": _2, + "space": [1, { + "myfast": _3, + "uber": _3, + "xs4all": _3 + }], + "sport": _2, + "spot": _2, + "srl": _2, + "stada": _2, + "staples": _2, + "star": _2, + "statebank": _2, + "statefarm": _2, + "stc": _2, + "stcgroup": _2, + "stockholm": _2, + "storage": _2, + "store": [1, { + "sellfy": _3, + "shopware": _3, + "storebase": _3 + }], + "stream": _2, + "studio": _2, + "study": _2, + "style": _2, + "sucks": _2, + "supplies": _2, + "supply": _2, + "support": _52, + "surf": _2, + "surgery": _2, + "suzuki": _2, + "swatch": _2, + "swiss": _2, + "sydney": _2, + "systems": [1, { + "knightpoint": _3 + }], + "tab": _2, + "taipei": _2, + "talk": _2, + "taobao": _2, + "target": _2, + "tatamotors": _2, + "tatar": _2, + "tattoo": _2, + "tax": _2, + "taxi": _2, + "tci": _2, + "tdk": _2, + "team": [1, { + "discourse": _3, + "jelastic": _3 + }], + "tech": _2, + "technology": _15, + "temasek": _2, + "tennis": _2, + "teva": _2, + "thd": _2, + "theater": _2, + "theatre": _2, + "tiaa": _2, + "tickets": _2, + "tienda": _2, + "tips": _2, + "tires": _2, + "tirol": _2, + "tjmaxx": _2, + "tjx": _2, + "tkmaxx": _2, + "tmall": _2, + "today": [1, { + "prequalifyme": _3 + }], + "tokyo": _2, + "tools": _2, + "top": [1, { + "now-dns": _3, + "ntdll": _3 + }], + "toray": _2, + "toshiba": _2, + "total": _2, + "tours": _2, + "town": _2, + "toyota": _2, + "toys": _2, + "trade": _44, + "trading": _2, + "training": _2, + "travel": _2, + "travelers": _2, + "travelersinsurance": _2, + "trust": _2, + "trv": _2, + "tube": _2, + "tui": _2, + "tunes": _2, + "tushu": _2, + "tvs": _2, + "ubank": _2, + "ubs": _2, + "unicom": _2, + "university": _2, + "uno": _2, + "uol": _2, + "ups": _2, + "vacations": _2, + "vana": _2, + "vanguard": _2, + "vegas": _2, + "ventures": _2, + "verisign": _2, + "versicherung": _2, + "vet": _2, + "viajes": _2, + "video": _2, + "vig": _2, + "viking": _2, + "villas": _2, + "vin": _2, + "vip": _2, + "virgin": _2, + "visa": _2, + "vision": _2, + "viva": _2, + "vivo": _2, + "vlaanderen": _2, + "vodka": _2, + "volvo": _2, + "vote": _2, + "voting": _2, + "voto": _2, + "voyage": _2, + "wales": _2, + "walmart": _2, + "walter": _2, + "wang": _2, + "wanggou": _2, + "watch": _2, + "watches": _2, + "weather": _2, + "weatherchannel": _2, + "webcam": _2, + "weber": _2, + "website": _51, + "wed": _2, + "wedding": _2, + "weibo": _2, + "weir": _2, + "whoswho": _2, + "wien": _2, + "wiki": _51, + "williamhill": _2, + "win": _2, + "windows": _2, + "wine": _2, + "winners": _2, + "wme": _2, + "wolterskluwer": _2, + "woodside": _2, + "work": _2, + "works": _2, + "world": _2, + "wow": _2, + "wtc": _2, + "wtf": _2, + "xbox": _2, + "xerox": _2, + "xihuan": _2, + "xin": _2, + "xn--11b4c3d": _2, + "कॉम": _2, + "xn--1ck2e1b": _2, + "セール": _2, + "xn--1qqw23a": _2, + "佛山": _2, + "xn--30rr7y": _2, + "慈善": _2, + "xn--3bst00m": _2, + "集团": _2, + "xn--3ds443g": _2, + "在线": _2, + "xn--3pxu8k": _2, + "点看": _2, + "xn--42c2d9a": _2, + "คอม": _2, + "xn--45q11c": _2, + "å…«å¦": _2, + "xn--4gbrim": _2, + "موقع": _2, + "xn--55qw42g": _2, + "公益": _2, + "xn--55qx5d": _2, + "å…¬å¸": _2, + "xn--5su34j936bgsg": _2, + "香格里拉": _2, + "xn--5tzm5g": _2, + "网站": _2, + "xn--6frz82g": _2, + "移动": _2, + "xn--6qq986b3xl": _2, + "我爱你": _2, + "xn--80adxhks": _2, + "моÑква": _2, + "xn--80aqecdr1a": _2, + "католик": _2, + "xn--80asehdb": _2, + "онлайн": _2, + "xn--80aswg": _2, + "Ñайт": _2, + "xn--8y0a063a": _2, + "è”通": _2, + "xn--9dbq2a": _2, + "קו×": _2, + "xn--9et52u": _2, + "æ—¶å°š": _2, + "xn--9krt00a": _2, + "å¾®åš": _2, + "xn--b4w605ferd": _2, + "淡马锡": _2, + "xn--bck1b9a5dre4c": _2, + "ファッション": _2, + "xn--c1avg": _2, + "орг": _2, + "xn--c2br7g": _2, + "नेट": _2, + "xn--cck2b3b": _2, + "ストア": _2, + "xn--cckwcxetd": _2, + "アマゾン": _2, + "xn--cg4bki": _2, + "삼성": _2, + "xn--czr694b": _2, + "商标": _2, + "xn--czrs0t": _2, + "商店": _2, + "xn--czru2d": _2, + "商城": _2, + "xn--d1acj3b": _2, + "дети": _2, + "xn--eckvdtc9d": _2, + "ãƒã‚¤ãƒ³ãƒˆ": _2, + "xn--efvy88h": _2, + "æ–°é—»": _2, + "xn--fct429k": _2, + "å®¶é›»": _2, + "xn--fhbei": _2, + "كوم": _2, + "xn--fiq228c5hs": _2, + "中文网": _2, + "xn--fiq64b": _2, + "中信": _2, + "xn--fjq720a": _2, + "娱ä¹": _2, + "xn--flw351e": _2, + "è°·æ­Œ": _2, + "xn--fzys8d69uvgm": _2, + "電訊盈科": _2, + "xn--g2xx48c": _2, + "购物": _2, + "xn--gckr3f0f": _2, + "クラウド": _2, + "xn--gk3at1e": _2, + "通販": _2, + "xn--hxt814e": _2, + "网店": _2, + "xn--i1b6b1a6a2e": _2, + "संगठन": _2, + "xn--imr513n": _2, + "é¤åŽ…": _2, + "xn--io0a7i": _2, + "网络": _2, + "xn--j1aef": _2, + "ком": _2, + "xn--jlq480n2rg": _2, + "亚马逊": _2, + "xn--jvr189m": _2, + "食å“": _2, + "xn--kcrx77d1x4a": _2, + "飞利浦": _2, + "xn--kput3i": _2, + "手机": _2, + "xn--mgba3a3ejt": _2, + "ارامكو": _2, + "xn--mgba7c0bbn0a": _2, + "العليان": _2, + "xn--mgbab2bd": _2, + "بازار": _2, + "xn--mgbca7dzdo": _2, + "ابوظبي": _2, + "xn--mgbi4ecexp": _2, + "كاثوليك": _2, + "xn--mgbt3dhd": _2, + "همراه": _2, + "xn--mk1bu44c": _2, + "ë‹·ì»´": _2, + "xn--mxtq1m": _2, + "政府": _2, + "xn--ngbc5azd": _2, + "شبكة": _2, + "xn--ngbe9e0a": _2, + "بيتك": _2, + "xn--ngbrx": _2, + "عرب": _2, + "xn--nqv7f": _2, + "机构": _2, + "xn--nqv7fs00ema": _2, + "组织机构": _2, + "xn--nyqy26a": _2, + "å¥åº·": _2, + "xn--otu796d": _2, + "æ‹›è˜": _2, + "xn--p1acf": [1, { + "xn--90amc": _3, + "xn--j1aef": _3, + "xn--j1ael8b": _3, + "xn--h1ahn": _3, + "xn--j1adp": _3, + "xn--c1avg": _3, + "xn--80aaa0cvac": _3, + "xn--h1aliz": _3, + "xn--90a1af": _3, + "xn--41a": _3 + }], + "руÑ": [1, { + "биз": _3, + "ком": _3, + "крым": _3, + "мир": _3, + "мÑк": _3, + "орг": _3, + "Ñамара": _3, + "Ñочи": _3, + "Ñпб": _3, + "Ñ": _3 + }], + "xn--pssy2u": _2, + "大拿": _2, + "xn--q9jyb4c": _2, + "ã¿ã‚“ãª": _2, + "xn--qcka1pmc": _2, + "グーグル": _2, + "xn--rhqv96g": _2, + "世界": _2, + "xn--rovu88b": _2, + "書ç±": _2, + "xn--ses554g": _2, + "网å€": _2, + "xn--t60b56a": _2, + "ë‹·ë„·": _2, + "xn--tckwe": _2, + "コム": _2, + "xn--tiq49xqyj": _2, + "天主教": _2, + "xn--unup4y": _2, + "游æˆ": _2, + "xn--vermgensberater-ctb": _2, + "vermögensberater": _2, + "xn--vermgensberatung-pwb": _2, + "vermögensberatung": _2, + "xn--vhquv": _2, + "ä¼ä¸š": _2, + "xn--vuq861b": _2, + "ä¿¡æ¯": _2, + "xn--w4r85el8fhu5dnra": _2, + "嘉里大酒店": _2, + "xn--w4rs40l": _2, + "嘉里": _2, + "xn--xhq521b": _2, + "广东": _2, + "xn--zfr164b": _2, + "政务": _2, + "xyz": [1, { + "blogsite": _3, + "localzone": _3, + "crafting": _3, + "zapto": _3, + "telebit": _5 + }], + "yachts": _2, + "yahoo": _2, + "yamaxun": _2, + "yandex": _2, + "yodobashi": _2, + "yoga": _2, + "yokohama": _2, + "you": _2, + "youtube": _2, + "yun": _2, + "zappos": _2, + "zara": _2, + "zero": _2, + "zip": _2, + "zone": [1, { + "cloud66": _3, + "hs": _3, + "triton": _5, + "stackit": _3, + "lima": _3 + }], + "zuerich": _2 + }]; + return rules; +}(); +;// CONCATENATED MODULE: ../../node_modules/tldts/dist/es6/src/suffix-trie.js + + +/** + * Lookup parts of domain in Trie + */ +function lookupInTrie(parts, trie, index, allowedMask) { + let result = null; + let node = trie; + while (node !== undefined) { + // We have a match! + if ((node[0] & allowedMask) !== 0) { + result = { + index: index + 1, + isIcann: node[0] === 1 /* RULE_TYPE.ICANN */, + isPrivate: node[0] === 2 /* RULE_TYPE.PRIVATE */ + }; + } + // No more `parts` to look for + if (index === -1) { + break; + } + const succ = node[1]; + node = Object.prototype.hasOwnProperty.call(succ, parts[index]) ? succ[parts[index]] : succ['*']; + index -= 1; + } + return result; +} +/** + * Check if `hostname` has a valid public suffix in `trie`. + */ +function suffix_trie_suffixLookup(hostname, options, out) { + var _a; + if (fast_path(hostname, options, out)) { + return; + } + const hostnameParts = hostname.split('.'); + const allowedMask = (options.allowPrivateDomains ? 2 /* RULE_TYPE.PRIVATE */ : 0) | (options.allowIcannDomains ? 1 /* RULE_TYPE.ICANN */ : 0); + // Look for exceptions + const exceptionMatch = lookupInTrie(hostnameParts, exceptions, hostnameParts.length - 1, allowedMask); + if (exceptionMatch !== null) { + out.isIcann = exceptionMatch.isIcann; + out.isPrivate = exceptionMatch.isPrivate; + out.publicSuffix = hostnameParts.slice(exceptionMatch.index + 1).join('.'); + return; + } + // Look for a match in rules + const rulesMatch = lookupInTrie(hostnameParts, rules, hostnameParts.length - 1, allowedMask); + if (rulesMatch !== null) { + out.isIcann = rulesMatch.isIcann; + out.isPrivate = rulesMatch.isPrivate; + out.publicSuffix = hostnameParts.slice(rulesMatch.index).join('.'); + return; + } + // No match found... + // Prevailing rule is '*' so we consider the top-level domain to be the + // public suffix of `hostname` (e.g.: 'example.org' => 'org'). + out.isIcann = false; + out.isPrivate = false; + out.publicSuffix = (_a = hostnameParts[hostnameParts.length - 1]) !== null && _a !== void 0 ? _a : null; +} +;// CONCATENATED MODULE: ../../node_modules/tldts/dist/es6/index.js + + +// For all methods but 'parse', it does not make sense to allocate an object +// every single time to only return the value of a specific attribute. To avoid +// this un-necessary allocation, we use a global object which is re-used. +const RESULT = getEmptyResult(); +function parse(url, options = {}) { + return factory_parseImpl(url, 5 /* FLAG.ALL */, suffix_trie_suffixLookup, options, getEmptyResult()); +} +function getHostname(url, options = {}) { + /*@__INLINE__*/factory_resetResult(RESULT); + return factory_parseImpl(url, 0 /* FLAG.HOSTNAME */, suffix_trie_suffixLookup, options, RESULT).hostname; +} +function getPublicSuffix(url, options = {}) { + /*@__INLINE__*/resetResult(RESULT); + return parseImpl(url, 2 /* FLAG.PUBLIC_SUFFIX */, suffixLookup, options, RESULT).publicSuffix; +} +function es6_getDomain(url, options = {}) { + /*@__INLINE__*/resetResult(RESULT); + return parseImpl(url, 3 /* FLAG.DOMAIN */, suffixLookup, options, RESULT).domain; +} +function es6_getSubdomain(url, options = {}) { + /*@__INLINE__*/resetResult(RESULT); + return parseImpl(url, 4 /* FLAG.SUB_DOMAIN */, suffixLookup, options, RESULT).subdomain; +} +function es6_getDomainWithoutSuffix(url, options = {}) { + /*@__INLINE__*/resetResult(RESULT); + return parseImpl(url, 5 /* FLAG.ALL */, suffixLookup, options, RESULT).domainWithoutSuffix; +} +;// CONCATENATED MODULE: ../../libs/common/src/platform/misc/utils.ts +/* provided dependency */ var utils_process = __webpack_require__(71624); +/* eslint-disable no-useless-escape */ + + + + +const nodeURL = typeof window === "undefined" ? __webpack_require__(69573) : null; +class Utils { + static init() { + if (Utils.inited) { + return; + } + Utils.inited = true; + Utils.isNode = + typeof utils_process !== "undefined" && + utils_process.release != null && + utils_process.release.name === "node"; + Utils.isBrowser = typeof window !== "undefined"; + Utils.isMobileBrowser = Utils.isBrowser && this.isMobile(window); + Utils.isAppleMobileBrowser = Utils.isBrowser && this.isAppleMobile(window); + if (Utils.isNode) { + Utils.global = __webpack_require__.g; + } + else if (Utils.isBrowser) { + Utils.global = window; + } + else { + // If it's not browser or node then it must be a service worker + Utils.global = self; + } + } + static fromB64ToArray(str) { + if (str == null) { + return null; + } + if (Utils.isNode) { + return new Uint8Array(Buffer.from(str, "base64")); + } + else { + const binaryString = Utils.global.atob(str); + const bytes = new Uint8Array(binaryString.length); + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes; + } + } + static fromUrlB64ToArray(str) { + return Utils.fromB64ToArray(Utils.fromUrlB64ToB64(str)); + } + static fromHexToArray(str) { + if (Utils.isNode) { + return new Uint8Array(Buffer.from(str, "hex")); + } + else { + const bytes = new Uint8Array(str.length / 2); + for (let i = 0; i < str.length; i += 2) { + bytes[i / 2] = parseInt(str.substr(i, 2), 16); + } + return bytes; + } + } + static fromUtf8ToArray(str) { + if (Utils.isNode) { + return new Uint8Array(Buffer.from(str, "utf8")); + } + else { + const strUtf8 = unescape(encodeURIComponent(str)); + const arr = new Uint8Array(strUtf8.length); + for (let i = 0; i < strUtf8.length; i++) { + arr[i] = strUtf8.charCodeAt(i); + } + return arr; + } + } + static fromByteStringToArray(str) { + if (str == null) { + return null; + } + const arr = new Uint8Array(str.length); + for (let i = 0; i < str.length; i++) { + arr[i] = str.charCodeAt(i); + } + return arr; + } + static fromBufferToB64(buffer) { + if (buffer == null) { + return null; + } + if (Utils.isNode) { + return Buffer.from(buffer).toString("base64"); + } + else { + let binary = ""; + const bytes = new Uint8Array(buffer); + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]); + } + return Utils.global.btoa(binary); + } + } + static fromBufferToUrlB64(buffer) { + return Utils.fromB64toUrlB64(Utils.fromBufferToB64(buffer)); + } + static fromB64toUrlB64(b64Str) { + return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + } + static fromBufferToUtf8(buffer) { + return node_modules_buffer/* Buffer */.lW.from(buffer).toString("utf8"); + } + static fromBufferToByteString(buffer) { + return String.fromCharCode.apply(null, new Uint8Array(buffer)); + } + // ref: https://stackoverflow.com/a/40031979/1090359 + static fromBufferToHex(buffer) { + if (Utils.isNode) { + return Buffer.from(buffer).toString("hex"); + } + else { + const bytes = new Uint8Array(buffer); + return Array.prototype.map + .call(bytes, (x) => ("00" + x.toString(16)).slice(-2)) + .join(""); + } + } + /** + * Converts a hex string to an ArrayBuffer. + * Note: this doesn't need any Node specific code as parseInt() / ArrayBuffer / Uint8Array + * work the same in Node and the browser. + * @param {string} hexString - A string of hexadecimal characters. + * @returns {ArrayBuffer} The ArrayBuffer representation of the hex string. + */ + static hexStringToArrayBuffer(hexString) { + // Check if the hexString has an even length, as each hex digit represents half a byte (4 bits), + // and it takes two hex digits to represent a full byte (8 bits). + if (hexString.length % 2 !== 0) { + throw "HexString has to be an even length"; + } + // Create an ArrayBuffer with a length that is half the length of the hex string, + // because each pair of hex digits will become a single byte. + const arrayBuffer = new ArrayBuffer(hexString.length / 2); + // Create a Uint8Array view on top of the ArrayBuffer (each position represents a byte) + // as ArrayBuffers cannot be edited directly. + const uint8Array = new Uint8Array(arrayBuffer); + // Loop through the bytes + for (let i = 0; i < uint8Array.length; i++) { + // Extract two hex characters (1 byte) + const hexByte = hexString.substr(i * 2, 2); + // Convert hexByte into a decimal value from base 16. (ex: ff --> 255) + const byteValue = parseInt(hexByte, 16); + // Place the byte value into the uint8Array + uint8Array[i] = byteValue; + } + return arrayBuffer; + } + static fromUrlB64ToB64(urlB64Str) { + let output = urlB64Str.replace(/-/g, "+").replace(/_/g, "/"); + switch (output.length % 4) { + case 0: + break; + case 2: + output += "=="; + break; + case 3: + output += "="; + break; + default: + throw new Error("Illegal base64url string!"); + } + return output; + } + static fromUrlB64ToUtf8(urlB64Str) { + return Utils.fromB64ToUtf8(Utils.fromUrlB64ToB64(urlB64Str)); + } + static fromUtf8ToB64(utfStr) { + if (Utils.isNode) { + return Buffer.from(utfStr, "utf8").toString("base64"); + } + else { + return decodeURIComponent(escape(Utils.global.btoa(utfStr))); + } + } + static fromUtf8ToUrlB64(utfStr) { + return Utils.fromBufferToUrlB64(Utils.fromUtf8ToArray(utfStr)); + } + static fromB64ToUtf8(b64Str) { + if (Utils.isNode) { + return Buffer.from(b64Str, "base64").toString("utf8"); + } + else { + return decodeURIComponent(escape(Utils.global.atob(b64Str))); + } + } + // ref: http://stackoverflow.com/a/2117523/1090359 + static newGuid() { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (Math.random() * 16) | 0; + const v = c === "x" ? r : (r & 0x3) | 0x8; + return v.toString(16); + }); + } + static isGuid(id) { + return RegExp(Utils.guidRegex, "i").test(id); + } + static getHostname(uriString) { + if (Utils.isNullOrWhitespace(uriString)) { + return null; + } + uriString = uriString.trim(); + if (uriString.startsWith("data:")) { + return null; + } + if (uriString.startsWith("about:")) { + return null; + } + if (uriString.startsWith("file:")) { + return null; + } + // Does uriString contain invalid characters + // TODO Needs to possibly be extended, although '!' is a reserved character + if (uriString.indexOf("!") > 0) { + return null; + } + try { + const hostname = getHostname(uriString, { validHosts: this.validHosts }); + if (hostname != null) { + return hostname; + } + } + catch (_a) { + return null; + } + return null; + } + static getHost(uriString) { + const url = Utils.getUrl(uriString); + try { + return url != null && url.host !== "" ? url.host : null; + } + catch (_a) { + return null; + } + } + static getDomain(uriString) { + if (Utils.isNullOrWhitespace(uriString)) { + return null; + } + uriString = uriString.trim(); + if (uriString.startsWith("data:")) { + return null; + } + if (uriString.startsWith("about:")) { + return null; + } + try { + const parseResult = parse(uriString, { + validHosts: this.validHosts, + allowPrivateDomains: true, + }); + if (parseResult != null && parseResult.hostname != null) { + if (parseResult.hostname === "localhost" || parseResult.isIp) { + return parseResult.hostname; + } + if (parseResult.domain != null) { + return parseResult.domain; + } + return null; + } + } + catch (_a) { + return null; + } + return null; + } + static getQueryParams(uriString) { + const url = Utils.getUrl(uriString); + if (url == null || url.search == null || url.search === "") { + return null; + } + const map = new Map(); + const pairs = (url.search[0] === "?" ? url.search.substr(1) : url.search).split("&"); + pairs.forEach((pair) => { + const parts = pair.split("="); + if (parts.length < 1) { + return; + } + map.set(decodeURIComponent(parts[0]).toLowerCase(), parts[1] == null ? "" : decodeURIComponent(parts[1])); + }); + return map; + } + static getSortFunction(i18nService, prop) { + return (a, b) => { + if (a[prop] == null && b[prop] != null) { + return -1; + } + if (a[prop] != null && b[prop] == null) { + return 1; + } + if (a[prop] == null && b[prop] == null) { + return 0; + } + // The `as unknown as string` here is unfortunate because typescript doesn't property understand that the return of T[prop] will be a string + return i18nService.collator + ? i18nService.collator.compare(a[prop], b[prop]) + : a[prop].localeCompare(b[prop]); + }; + } + static isNullOrWhitespace(str) { + return str == null || typeof str !== "string" || str.trim() === ""; + } + static isNullOrEmpty(str) { + return str == null || typeof str !== "string" || str == ""; + } + static isPromise(obj) { + return (obj != undefined && typeof obj["then"] === "function" && typeof obj["catch"] === "function"); + } + static nameOf(name) { + return name; + } + static assign(target, source) { + return Object.assign(target, source); + } + static iterateEnum(obj) { + return Object.keys(obj).filter((k) => Number.isNaN(+k)).map((k) => obj[k]); + } + static getUrl(uriString) { + if (this.isNullOrWhitespace(uriString)) { + return null; + } + uriString = uriString.trim(); + return Utils.getUrlObject(uriString); + } + static camelToPascalCase(s) { + return s.charAt(0).toUpperCase() + s.slice(1); + } + /** + * There are a few ways to calculate text color for contrast, this one seems to fit accessibility guidelines best. + * https://stackoverflow.com/a/3943023/6869691 + * + * @param {string} bgColor + * @param {number} [threshold] see stackoverflow link above + * @param {boolean} [svgTextFill] + * Indicates if this method is performed on an SVG 'fill' attribute (e.g. ). + * This check is necessary because the '!important' tag cannot be used in a 'fill' attribute. + */ + static pickTextColorBasedOnBgColor(bgColor, threshold = 186, svgTextFill = false) { + const bgColorHexNums = bgColor.charAt(0) === "#" ? bgColor.substring(1, 7) : bgColor; + const r = parseInt(bgColorHexNums.substring(0, 2), 16); // hexToR + const g = parseInt(bgColorHexNums.substring(2, 4), 16); // hexToG + const b = parseInt(bgColorHexNums.substring(4, 6), 16); // hexToB + const blackColor = svgTextFill ? "black" : "black !important"; + const whiteColor = svgTextFill ? "white" : "white !important"; + return r * 0.299 + g * 0.587 + b * 0.114 > threshold ? blackColor : whiteColor; + } + static stringToColor(str) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + let color = "#"; + for (let i = 0; i < 3; i++) { + const value = (hash >> (i * 8)) & 0xff; + color += ("00" + value.toString(16)).substr(-2); + } + return color; + } + /** + * @throws Will throw an error if the ContainerService has not been attached to the window object + */ + static getContainerService() { + if (this.global.bitwardenContainerService == null) { + throw new Error("global bitwardenContainerService not initialized."); + } + return this.global.bitwardenContainerService; + } + static validateHexColor(color) { + return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color); + } + /** + * Converts map to a Record with the same data. Inverse of recordToMap + * Useful in toJSON methods, since Maps are not serializable + * @param map + * @returns + */ + static mapToRecord(map) { + if (map == null) { + return null; + } + if (!(map instanceof Map)) { + return map; + } + return Object.fromEntries(map); + } + /** + * Converts record to a Map with the same data. Inverse of mapToRecord + * Useful in fromJSON methods, since Maps are not serializable + * + * Warning: If the record has string keys that are numbers, they will be converted to numbers in the map + * @param record + * @returns + */ + static recordToMap(record) { + if (record == null) { + return null; + } + else if (record instanceof Map) { + return record; + } + const entries = Object.entries(record); + if (entries.length === 0) { + return new Map(); + } + if (isNaN(Number(entries[0][0]))) { + return new Map(entries); + } + else { + return new Map(entries.map((e) => [Number(e[0]), e[1]])); + } + } + /** Applies Object.assign, but converts the type nicely using Type-Fest Merge */ + static merge(destination, source) { + return Object.assign(destination, source); + } + /** + * encodeURIComponent escapes all characters except the following: + * alphabetic, decimal digits, - _ . ! ~ * ' ( ) + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#encoding_for_rfc3986 + */ + static encodeRFC3986URIComponent(str) { + return encodeURIComponent(str).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`); + } + /** + * Normalizes a path for defense against attacks like traversals + * @param denormalizedPath + * @returns + */ + static normalizePath(denormalizedPath) { + return path_browserify.normalize(decodeURIComponent(denormalizedPath)).replace(/^(\.\.(\/|\\|$))+/, ""); + } + static isMobile(win) { + let mobile = false; + ((a) => { + if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || + /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) { + mobile = true; + } + })(win.navigator.userAgent || win.navigator.vendor || win.opera); + return mobile || win.navigator.userAgent.match(/iPad/i) != null; + } + static delay(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + /** + * Generate an observable from a function that returns a promise. + * Similar to the rxjs function {@link from} with one big exception: + * {@link from} will not re-execute the function when observers resubscribe. + * {@link Util.asyncToObservable} will execute `generator` for every + * subscribe, making it ideal if the value ever needs to be refreshed. + * */ + static asyncToObservable(generator) { + return of(undefined).pipe(switchMap(() => generator())); + } + /** + * Return the number of days remaining before a target date arrives. + * Returns 0 if the day has already passed. + */ + static daysRemaining(targetDate) { + const diffTime = targetDate.getTime() - Date.now(); + const msPerDay = 86400000; + return Math.max(0, Math.floor(diffTime / msPerDay)); + } + static isAppleMobile(win) { + return (win.navigator.userAgent.match(/iPhone/i) != null || + win.navigator.userAgent.match(/iPad/i) != null); + } + static getUrlObject(uriString) { + // All the methods below require a protocol to properly parse a URL string + // Assume http if no other protocol is present + const hasProtocol = uriString.indexOf("://") > -1; + if (!hasProtocol && uriString.indexOf(".") > -1) { + uriString = "http://" + uriString; + } + else if (!hasProtocol) { + return null; + } + try { + if (nodeURL != null) { + return new nodeURL.URL(uriString); + } + return new URL(uriString); + } + catch (e) { + // Ignore error + } + return null; + } +} +Utils.inited = false; +Utils.isNode = false; +Utils.isBrowser = true; +Utils.isMobileBrowser = false; +Utils.isAppleMobileBrowser = false; +Utils.global = null; +// Transpiled version of /\p{Emoji_Presentation}/gu using https://mothereff.in/regexpu. Used for compatability in older browsers. +Utils.regexpEmojiPresentation = /(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5-\uDED7\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB]|\uD83E[\uDD0C-\uDD3A\uDD3C-\uDD45\uDD47-\uDD78\uDD7A-\uDDCB\uDDCD-\uDDFF\uDE70-\uDE74\uDE78-\uDE7A\uDE80-\uDE86\uDE90-\uDEA8\uDEB0-\uDEB6\uDEC0-\uDEC2\uDED0-\uDED6])/g; +Utils.validHosts = ["localhost"]; +Utils.originalMinimumPasswordLength = 8; +Utils.minimumPasswordLength = 12; +Utils.DomainMatchBlacklist = new Map([ + ["google.com", new Set(["script.google.com"])], +]); +Utils.guidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/; +Utils.init(); + +;// CONCATENATED MODULE: ../../libs/common/src/vault/services/fido2/fido2-utils.ts + +class Fido2Utils { + static bufferToString(bufferSource) { + const buffer = Fido2Utils.bufferSourceToUint8Array(bufferSource); + return Utils.fromBufferToUrlB64(buffer); + } + static stringToBuffer(str) { + return Utils.fromUrlB64ToArray(str); + } + static bufferSourceToUint8Array(bufferSource) { + if (Fido2Utils.isArrayBuffer(bufferSource)) { + return new Uint8Array(bufferSource); + } + else { + return new Uint8Array(bufferSource.buffer); + } + } + /** Utility function to identify type of bufferSource. Necessary because of differences between runtimes */ + static isArrayBuffer(bufferSource) { + return bufferSource instanceof ArrayBuffer || bufferSource.buffer === undefined; + } +} + +;// CONCATENATED MODULE: ./src/vault/fido2/webauthn-utils.ts + +class WebauthnUtils { + static mapCredentialCreationOptions(options, fallbackSupported) { + var _a, _b, _c, _d, _e; + const keyOptions = options.publicKey; + if (keyOptions == undefined) { + throw new Error("Public-key options not found"); + } + return { + attestation: keyOptions.attestation, + authenticatorSelection: { + requireResidentKey: (_a = keyOptions.authenticatorSelection) === null || _a === void 0 ? void 0 : _a.requireResidentKey, + residentKey: (_b = keyOptions.authenticatorSelection) === null || _b === void 0 ? void 0 : _b.residentKey, + userVerification: (_c = keyOptions.authenticatorSelection) === null || _c === void 0 ? void 0 : _c.userVerification, + }, + challenge: Fido2Utils.bufferToString(keyOptions.challenge), + excludeCredentials: (_d = keyOptions.excludeCredentials) === null || _d === void 0 ? void 0 : _d.map((credential) => ({ + id: Fido2Utils.bufferToString(credential.id), + transports: credential.transports, + type: credential.type, + })), + extensions: { + credProps: (_e = keyOptions.extensions) === null || _e === void 0 ? void 0 : _e.credProps, + }, + pubKeyCredParams: keyOptions.pubKeyCredParams.map((params) => ({ + alg: params.alg, + type: params.type, + })), + rp: { + id: keyOptions.rp.id, + name: keyOptions.rp.name, + }, + user: { + id: Fido2Utils.bufferToString(keyOptions.user.id), + displayName: keyOptions.user.displayName, + name: keyOptions.user.name, + }, + timeout: keyOptions.timeout, + fallbackSupported, + }; + } + static mapCredentialRegistrationResult(result) { + const credential = { + id: result.credentialId, + rawId: Fido2Utils.stringToBuffer(result.credentialId), + type: "public-key", + authenticatorAttachment: "platform", + response: { + clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON), + attestationObject: Fido2Utils.stringToBuffer(result.attestationObject), + getAuthenticatorData() { + return Fido2Utils.stringToBuffer(result.authData); + }, + getPublicKey() { + return Fido2Utils.stringToBuffer(result.publicKey); + }, + getPublicKeyAlgorithm() { + return result.publicKeyAlgorithm; + }, + getTransports() { + return result.transports; + }, + }, + getClientExtensionResults: () => ({ + credProps: result.extensions.credProps, + }), + }; + // Modify prototype chains to fix `instanceof` calls. + // This makes these objects indistinguishable from the native classes. + // Unfortunately PublicKeyCredential does not have a javascript constructor so `extends` does not work here. + Object.setPrototypeOf(credential.response, AuthenticatorAttestationResponse.prototype); + Object.setPrototypeOf(credential, PublicKeyCredential.prototype); + return credential; + } + static mapCredentialRequestOptions(options, fallbackSupported) { + var _a, _b; + const keyOptions = options.publicKey; + if (keyOptions == undefined) { + throw new Error("Public-key options not found"); + } + return { + allowedCredentialIds: (_b = (_a = keyOptions.allowCredentials) === null || _a === void 0 ? void 0 : _a.map((c) => Fido2Utils.bufferToString(c.id))) !== null && _b !== void 0 ? _b : [], + challenge: Fido2Utils.bufferToString(keyOptions.challenge), + rpId: keyOptions.rpId, + userVerification: keyOptions.userVerification, + timeout: keyOptions.timeout, + fallbackSupported, + }; + } + static mapCredentialAssertResult(result) { + const credential = { + id: result.credentialId, + rawId: Fido2Utils.stringToBuffer(result.credentialId), + type: "public-key", + response: { + authenticatorData: Fido2Utils.stringToBuffer(result.authenticatorData), + clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON), + signature: Fido2Utils.stringToBuffer(result.signature), + userHandle: Fido2Utils.stringToBuffer(result.userHandle), + }, + getClientExtensionResults: () => ({}), + authenticatorAttachment: "platform", + }; + // Modify prototype chains to fix `instanceof` calls. + // This makes these objects indistinguishable from the native classes. + // Unfortunately PublicKeyCredential does not have a javascript constructor so `extends` does not work here. + Object.setPrototypeOf(credential.response, AuthenticatorAssertionResponse.prototype); + Object.setPrototypeOf(credential, PublicKeyCredential.prototype); + return credential; + } +} + +;// CONCATENATED MODULE: ./src/vault/fido2/content/messaging/message.ts +var MessageType; +(function (MessageType) { + MessageType[MessageType["CredentialCreationRequest"] = 0] = "CredentialCreationRequest"; + MessageType[MessageType["CredentialCreationResponse"] = 1] = "CredentialCreationResponse"; + MessageType[MessageType["CredentialGetRequest"] = 2] = "CredentialGetRequest"; + MessageType[MessageType["CredentialGetResponse"] = 3] = "CredentialGetResponse"; + MessageType[MessageType["AbortRequest"] = 4] = "AbortRequest"; + MessageType[MessageType["DisconnectRequest"] = 5] = "DisconnectRequest"; + MessageType[MessageType["ReconnectRequest"] = 6] = "ReconnectRequest"; + MessageType[MessageType["AbortResponse"] = 7] = "AbortResponse"; + MessageType[MessageType["ErrorResponse"] = 8] = "ErrorResponse"; +})(MessageType || (MessageType = {})); + +;// CONCATENATED MODULE: ./src/vault/fido2/content/messaging/messenger.ts +var messenger_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; + + +const SENDER = "bitwarden-webauthn"; +/** + * A class that handles communication between the page and content script. It converts + * the browser's broadcasting API into a request/response API with support for seamlessly + * handling aborts and exceptions across separate execution contexts. + */ +class Messenger { + /** + * Creates a messenger that uses the browser's `window.postMessage` API to initiate + * requests in the content script. Every request will then create it's own + * `MessageChannel` through which all subsequent communication will be sent through. + * + * @param window the window object to use for communication + * @returns a `Messenger` instance + */ + static forDOMCommunication(window) { + const windowOrigin = window.location.origin; + return new Messenger({ + postMessage: (message, port) => window.postMessage(message, windowOrigin, [port]), + addEventListener: (listener) => window.addEventListener("message", listener), + removeEventListener: (listener) => window.removeEventListener("message", listener), + }); + } + constructor(broadcastChannel) { + this.broadcastChannel = broadcastChannel; + this.messageEventListener = null; + this.onDestroy = new EventTarget(); + this.messengerId = this.generateUniqueId(); + this.messageEventListener = this.createMessageEventListener(); + this.broadcastChannel.addEventListener(this.messageEventListener); + } + /** + * Sends a request to the content script and returns the response. + * AbortController signals will be forwarded to the content script. + * + * @param request data to send to the content script + * @param abortController the abort controller that might be used to abort the request + * @returns the response from the content script + */ + request(request, abortController) { + return messenger_awaiter(this, void 0, void 0, function* () { + const requestChannel = new MessageChannel(); + const { port1: localPort, port2: remotePort } = requestChannel; + try { + const promise = new Promise((resolve) => { + localPort.onmessage = (event) => resolve(event.data); + }); + const abortListener = () => localPort.postMessage({ + metadata: { SENDER }, + type: MessageType.AbortRequest, + }); + abortController === null || abortController === void 0 ? void 0 : abortController.signal.addEventListener("abort", abortListener); + this.broadcastChannel.postMessage(Object.assign(Object.assign({}, request), { SENDER, senderId: this.messengerId }), remotePort); + const response = yield promise; + abortController === null || abortController === void 0 ? void 0 : abortController.signal.removeEventListener("abort", abortListener); + if (response.type === MessageType.ErrorResponse) { + const error = new Error(); + Object.assign(error, JSON.parse(response.error)); + throw error; + } + return response; + } + finally { + localPort.close(); + } + }); + } + createMessageEventListener() { + return (event) => messenger_awaiter(this, void 0, void 0, function* () { + var _a; + const windowOrigin = window.location.origin; + if (event.origin !== windowOrigin || !this.handler) { + return; + } + const message = event.data; + const port = (_a = event.ports) === null || _a === void 0 ? void 0 : _a[0]; + if ((message === null || message === void 0 ? void 0 : message.SENDER) !== SENDER || + message.senderId == this.messengerId || + message == null || + port == null) { + return; + } + const abortController = new AbortController(); + port.onmessage = (event) => { + if (event.data.type === MessageType.AbortRequest) { + abortController.abort(); + } + }; + let onDestroyListener; + const destroyPromise = new Promise((_, reject) => { + onDestroyListener = () => reject(new FallbackRequestedError()); + this.onDestroy.addEventListener("destroy", onDestroyListener); + }); + try { + const handlerResponse = yield Promise.race([ + this.handler(message, abortController), + destroyPromise, + ]); + port.postMessage(Object.assign(Object.assign({}, handlerResponse), { SENDER })); + } + catch (error) { + port.postMessage({ + SENDER, + type: MessageType.ErrorResponse, + error: JSON.stringify(error, Object.getOwnPropertyNames(error)), + }); + } + finally { + this.onDestroy.removeEventListener("destroy", onDestroyListener); + port.close(); + } + }); + } + /** + * Cleans up the messenger by removing the message event listener + */ + destroy() { + return messenger_awaiter(this, void 0, void 0, function* () { + this.onDestroy.dispatchEvent(new Event("destroy")); + if (this.messageEventListener) { + yield this.sendDisconnectCommand(); + this.broadcastChannel.removeEventListener(this.messageEventListener); + this.messageEventListener = null; + } + }); + } + sendReconnectCommand() { + return messenger_awaiter(this, void 0, void 0, function* () { + yield this.request({ type: MessageType.ReconnectRequest }); + }); + } + sendDisconnectCommand() { + return messenger_awaiter(this, void 0, void 0, function* () { + yield this.request({ type: MessageType.DisconnectRequest }); + }); + } + generateUniqueId() { + return Date.now().toString(36) + Math.random().toString(36).substring(2); + } +} + +;// CONCATENATED MODULE: ./src/vault/fido2/content/page-script.ts +var page_script_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; + + + + +const BrowserPublicKeyCredential = window.PublicKeyCredential; +const browserNativeWebauthnSupport = window.PublicKeyCredential != undefined; +let browserNativeWebauthnPlatformAuthenticatorSupport = false; +if (!browserNativeWebauthnSupport) { + // Polyfill webauthn support + try { + // credentials is read-only if supported, use type-casting to force assignment + navigator.credentials = { + create() { + return page_script_awaiter(this, void 0, void 0, function* () { + throw new Error("Webauthn not supported in this browser."); + }); + }, + get() { + return page_script_awaiter(this, void 0, void 0, function* () { + throw new Error("Webauthn not supported in this browser."); + }); + }, + }; + window.PublicKeyCredential = class PolyfillPublicKeyCredential { + static isUserVerifyingPlatformAuthenticatorAvailable() { + return Promise.resolve(true); + } + }; + window.AuthenticatorAttestationResponse = + class PolyfillAuthenticatorAttestationResponse { + }; + } + catch (_a) { + /* empty */ + } +} +if (browserNativeWebauthnSupport) { + // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. + // eslint-disable-next-line @typescript-eslint/no-floating-promises + BrowserPublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable().then((available) => { + browserNativeWebauthnPlatformAuthenticatorSupport = available; + if (!available) { + // Polyfill platform authenticator support + window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable = () => Promise.resolve(true); + } + }); +} +const browserCredentials = { + create: navigator.credentials.create.bind(navigator.credentials), + get: navigator.credentials.get.bind(navigator.credentials), +}; +const messenger = (window.messenger = Messenger.forDOMCommunication(window)); +navigator.credentials.create = createWebAuthnCredential; +navigator.credentials.get = getWebAuthnCredential; +/** + * Creates a new webauthn credential. + * + * @param options Options for creating new credentials. + * @param abortController Abort controller to abort the request if needed. + * @returns Promise that resolves to the new credential object. + */ +function createWebAuthnCredential(options, abortController) { + var _a, _b, _c, _d; + return page_script_awaiter(this, void 0, void 0, function* () { + if (!isWebauthnCall(options)) { + return yield browserCredentials.create(options); + } + const fallbackSupported = (((_b = (_a = options === null || options === void 0 ? void 0 : options.publicKey) === null || _a === void 0 ? void 0 : _a.authenticatorSelection) === null || _b === void 0 ? void 0 : _b.authenticatorAttachment) === "platform" && + browserNativeWebauthnPlatformAuthenticatorSupport) || + (((_d = (_c = options === null || options === void 0 ? void 0 : options.publicKey) === null || _c === void 0 ? void 0 : _c.authenticatorSelection) === null || _d === void 0 ? void 0 : _d.authenticatorAttachment) !== "platform" && + browserNativeWebauthnSupport); + try { + const response = yield messenger.request({ + type: MessageType.CredentialCreationRequest, + data: WebauthnUtils.mapCredentialCreationOptions(options, fallbackSupported), + }, abortController); + if (response.type !== MessageType.CredentialCreationResponse) { + throw new Error("Something went wrong."); + } + return WebauthnUtils.mapCredentialRegistrationResult(response.result); + } + catch (error) { + if (error && error.fallbackRequested && fallbackSupported) { + yield waitForFocus(); + return yield browserCredentials.create(options); + } + throw error; + } + }); +} +/** + * Retrieves a webauthn credential. + * + * @param options Options for creating new credentials. + * @param abortController Abort controller to abort the request if needed. + * @returns Promise that resolves to the new credential object. + */ +function getWebAuthnCredential(options, abortController) { + return page_script_awaiter(this, void 0, void 0, function* () { + if (!isWebauthnCall(options)) { + return yield browserCredentials.get(options); + } + const fallbackSupported = browserNativeWebauthnSupport; + try { + if ((options === null || options === void 0 ? void 0 : options.mediation) && options.mediation !== "optional") { + throw new FallbackRequestedError(); + } + const response = yield messenger.request({ + type: MessageType.CredentialGetRequest, + data: WebauthnUtils.mapCredentialRequestOptions(options, fallbackSupported), + }, abortController); + if (response.type !== MessageType.CredentialGetResponse) { + throw new Error("Something went wrong."); + } + return WebauthnUtils.mapCredentialAssertResult(response.result); + } + catch (error) { + if (error && error.fallbackRequested && fallbackSupported) { + yield waitForFocus(); + return yield browserCredentials.get(options); + } + throw error; + } + }); +} +function isWebauthnCall(options) { + return options && "publicKey" in options; +} +/** + * Wait for window to be focused. + * Safari doesn't allow scripts to trigger webauthn when window is not focused. + * + * @param fallbackWait How long to wait when the script is not able to add event listeners to `window.top`. Defaults to 500ms. + * @param timeout Maximum time to wait for focus in milliseconds. Defaults to 5 minutes. + * @returns Promise that resolves when window is focused, or rejects if timeout is reached. + */ +function waitForFocus(fallbackWait = 500, timeout = 5 * 60 * 1000) { + return page_script_awaiter(this, void 0, void 0, function* () { + try { + if (window.top.document.hasFocus()) { + return; + } + } + catch (_a) { + // Cannot access window.top due to cross-origin frame, fallback to waiting + return yield new Promise((resolve) => window.setTimeout(resolve, fallbackWait)); + } + let focusListener; + const focusPromise = new Promise((resolve) => { + focusListener = () => resolve(); + window.top.addEventListener("focus", focusListener); + }); + let timeoutId; + const timeoutPromise = new Promise((_, reject) => { + timeoutId = window.setTimeout(() => reject(new DOMException("The operation either timed out or was not allowed.", "AbortError")), timeout); + }); + try { + yield Promise.race([focusPromise, timeoutPromise]); + } + finally { + window.top.removeEventListener("focus", focusListener); + window.clearTimeout(timeoutId); + } + }); +} +/** + * Sets up a listener to handle cleanup or reconnection when the extension's + * context changes due to being reloaded or unloaded. + */ +messenger.handler = (message, abortController) => { + const type = message.type; + // Handle cleanup for disconnect request + if (type === MessageType.DisconnectRequest && browserNativeWebauthnSupport) { + navigator.credentials.create = browserCredentials.create; + navigator.credentials.get = browserCredentials.get; + } + // Handle reinitialization for reconnect request + if (type === MessageType.ReconnectRequest && browserNativeWebauthnSupport) { + navigator.credentials.create = createWebAuthnCredential; + navigator.credentials.get = getWebAuthnCredential; + } +}; + +})(); + +/******/ })() +; \ No newline at end of file diff --git a/scripts/crashlog.txt b/scripts/crashlog.txt new file mode 100644 index 0000000..5cbc0c6 --- /dev/null +++ b/scripts/crashlog.txt @@ -0,0 +1,4 @@ +#1 0x4025af sp=0x7fff3ff7c270 + 0x0 +#2 0x7f0b9234114a sp=0x7fff3ff7c290 __libc_start_call_main + 0x7a +#3 0x7f0b9234120b sp=0x7fff3ff7c330 __libc_start_main + 0x8b +#4 0x4025e5 sp=0x7fff3ff7c390 + 0x8b diff --git a/scripts/mqttd b/scripts/mqttd new file mode 100755 index 0000000..6d17d65 Binary files /dev/null and b/scripts/mqttd differ diff --git a/scripts/process_crashlog.py b/scripts/process_crashlog.py new file mode 100755 index 0000000..f1f4799 --- /dev/null +++ b/scripts/process_crashlog.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +from pathlib import Path +import shutil +import subprocess + + +class Crashlog(): + def __init__(self, crashlog: Path, executable: Path): + self.executable = executable + self.addresses = self.read_crashlog(crashlog) + self.translated_addresses = self.translate_addresses(self.addresses, executable) + + def read_crashlog(self, crashlog: Path) -> list[str]: + _addresses = [] + try: + with open(crashlog, "r") as f: + for line in f: + if len(line.strip()) <= 0: + continue + tokens = line.split() + _addresses.append(tokens[1]) + except FileNotFoundError: + print("O arquivo não foi encontrado.") + except Exception as e: + print(f"Ocorreu um error: {e}") + finally: + return _addresses + + def translate_addresses(self, addresses: list[str], executable: Path) -> dict[str, str]: + _translated_addr = {} + + if shutil.which("addr2line") is None: + raise RuntimeError("addr2line binary not found") + + for addr in addresses: + _path = executable.absolute() + _cmd = f"addr2line --functions --pretty-print --demangle --basenames --exe {_path} {addr}" + _process = subprocess.run(_cmd, shell=True, check=True, capture_output=True) + _translated_addr[addr] = _process.stdout + + return _translated_addr + + def __str__(self): + _stdout = "" + for key, value in self.translated_addresses.items(): + _stdout += value.decode() + return _stdout + + +if __name__ == "__main__": + print(Crashlog(Path("crashlog.txt"), Path("mqttd"))) + pass diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..8c878f2 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,7 @@ +[isort] +profile = black + +[pycodestyle] +max-line-length = 128 +ignore = E203,E701, E402, E501, E722 + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8ecb2a6..8f73d60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,13 @@ include(GetSpdlog) +include(GetCppTrace) add_subdirectory(libmqttd) add_subdirectory(core) add_executable(mqttd mqttd.cpp) -target_link_libraries(mqttd PRIVATE libcore libmqttd spdlog) +target_link_libraries(mqttd PRIVATE libcore libmqttd spdlog cpptrace::cpptrace) target_include_directories(mqttd PUBLIC "${PROJECT_BINARY_DIR}") + +add_executable(mqttd_stacktracer mqttd_stacktracer.cpp) +target_link_libraries(mqttd_stacktracer PRIVATE cpptrace::cpptrace) +target_include_directories(mqttd_stacktracer PUBLIC "${PROJECT_BINARY_DIR}") diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 04456a0..927a5ec 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,5 @@ add_library(libcore "") -add_subdirectory(backtrace) add_subdirectory(broker) FILE(GLOB CPP_FILES CONFIGURE_DEPENDS *.cpp) diff --git a/src/core/backtrace/CMakeLists.txt b/src/core/backtrace/CMakeLists.txt deleted file mode 100644 index cb83cf3..0000000 --- a/src/core/backtrace/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -FILE(GLOB CPP_FILES CONFIGURE_DEPENDS *.cpp) -FILE(GLOB HPP_FILES CONFIGURE_DEPENDS *.hpp) - -include(GetUnwind) - -target_sources(libcore - PRIVATE ${CPP_FILES} - PUBLIC ${HPP_FILES} -) - -target_link_libraries(libcore PRIVATE libunwind::static) -target_include_directories(libcore PUBLIC $ ${CMAKE_CURRENT_SOURCE_DIR}) - - diff --git a/src/core/backtrace/backtrace.cpp b/src/core/backtrace/backtrace.cpp deleted file mode 100644 index e8ba4cd..0000000 --- a/src/core/backtrace/backtrace.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "backtrace.hpp" - -void backtrace::backtrace() { - unw_cursor_t cursor; - unw_context_t context; - - unw_getcontext(&context); - unw_init_local(&cursor, &context); - - int n = 0; - while (unw_step(&cursor)) { - unw_word_t ip, sp, off; - - unw_get_reg(&cursor, UNW_REG_IP, &ip); - unw_get_reg(&cursor, UNW_REG_SP, &sp); - - char symbol[256] = {""}; - char *name = symbol; - - if (!unw_get_proc_name(&cursor, symbol, sizeof(symbol), &off)) { - int status; - if ((name = abi::__cxa_demangle(symbol, NULL, NULL, &status)) == 0) - name = symbol; - } - - printf("#%-2d 0x%016" PRIxPTR " sp=0x%016" PRIxPTR " %s + 0x%" PRIxPTR "\n", - ++n, static_cast(ip), static_cast(sp), name, - static_cast(off)); - - if (name != symbol) - free(name); - } - -} diff --git a/src/core/backtrace/backtrace.hpp b/src/core/backtrace/backtrace.hpp deleted file mode 100644 index 4436e45..0000000 --- a/src/core/backtrace/backtrace.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BACKTRACE_H -#define BACKTRACE_H - -#define __STDC_FORMAT_MACROS -#include - -#define UNW_LOCAL_ONLY -#include - -#include - -#include -#include -#include -#include - - -namespace backtrace { - void backtrace(); -} - -#endif /* end of include guard: BACKTRACE_H */ diff --git a/src/core/broker/connection_listener.cpp b/src/core/broker/connection_listener.cpp index 98df270..a789a1b 100644 --- a/src/core/broker/connection_listener.cpp +++ b/src/core/broker/connection_listener.cpp @@ -1,9 +1,6 @@ -#include "disconnect_packet.hpp" -#include "session.hpp" #include "session_manager.hpp" -#include #include -#include +#include #include ConnectionListener::ConnectionListener(int port) { this->connection_listener_port = port; } @@ -24,8 +21,7 @@ void ConnectionListener::join() { this->listener.join(); } -void ConnectionListener::create_new_session(int socket_fd) { -} +void ConnectionListener::create_new_session(int socket_fd) {} void ConnectionListener::listen() { struct sockaddr_in serverAddr; diff --git a/src/core/broker/connection_listener.hpp b/src/core/broker/connection_listener.hpp index 7efe334..74a37e0 100644 --- a/src/core/broker/connection_listener.hpp +++ b/src/core/broker/connection_listener.hpp @@ -3,33 +3,62 @@ #include #include -#include #include +#include +#include -#include #include - #include +#include -class ConnectionListener{ +/** + * @brief Class responsible for listening to incoming connections. + */ +class ConnectionListener { public: - + /** + * @brief Constructs a ConnectionListener object with the specified port. + * + * @param port The port to listen for incoming connections (default is 1883). + */ ConnectionListener(int port = 1883); + + /** + * @brief Destroys the ConnectionListener object. + */ ~ConnectionListener(); + + /** + * @brief Starts listening for incoming connections. + */ void start(); + + /** + * @brief Stops listening for incoming connections. + */ void stop(); + + /** + * @brief Joins the listener thread. + */ void join(); private: - bool is_listening; - int connection_listener_socket; - int connection_listener_port; - std::thread listener; + bool is_listening; /**< Flag indicating whether the listener is currently active. */ + int connection_listener_socket; /**< Socket file descriptor for the listener. */ + int connection_listener_port; /**< Port number to listen on. */ + std::thread listener; /**< Listener thread responsible for accepting incoming connections. */ + /** + * @brief Creates a new session for the accepted connection. + * + * @param socket_fd The socket file descriptor of the accepted connection. + */ static void create_new_session(int socket_fd); - // std::vector current_sessions; - + /** + * @brief Listens for incoming connections. + */ void listen(); }; diff --git a/src/core/broker/session_manager.hpp b/src/core/broker/session_manager.hpp index de5c3f8..373e8ce 100644 --- a/src/core/broker/session_manager.hpp +++ b/src/core/broker/session_manager.hpp @@ -6,34 +6,91 @@ #include #include +/** + * @brief Class responsible for managing MQTT sessions. + */ class SessionManager { public: - SessionManager(const SessionManager&) = delete; - SessionManager operator=(const SessionManager&) = delete; + /** + * @brief Deleted copy constructor. + */ + SessionManager(const SessionManager &) = delete; + /** + * @brief Deleted copy assignment operator. + */ + SessionManager operator=(const SessionManager &) = delete; + + /** + * @brief Retrieves the singleton instance of SessionManager. + * + * @return Reference to the singleton instance of SessionManager. + */ static SessionManager &get_instance(); + + /** + * @brief Destroys the SessionManager object. + */ ~SessionManager(); + /** + * @brief Creates a new session for the specified socket file descriptor. + * + * @param socket_fd The socket file descriptor for the new session. + */ void new_session(int socket_fd); + + /** + * @brief Shuts down the session with the given client ID. + * + * @param client_id The ID of the session to shut down. + */ void shutdown_session(const std::string &client_id); + + /** + * @brief Shuts down all active sessions. + */ void shutdown_all_sessions(); + + /** + * @brief Prints information about all active sessions. + */ void print_sessions(); private: - static SessionManager *singleton; - SessionManager() {}; + static SessionManager *singleton; /**< Pointer to the singleton instance of SessionManager. */ + SessionManager(){}; /**< Private constructor to prevent instantiation. */ + /** + * @brief Creates a new session for the specified socket file descriptor. + * + * @param socket_fd The socket file descriptor for the new session. + */ void create_session(int socket_fd); - void add_session_to_pool(Session *); - void remove_session_from_pool(Session *); - void check_for_session_takeover(const std::string&); + /** + * @brief Adds a session to the pool of connected sessions. + * + * @param session Pointer to the session to add. + */ + void add_session_to_pool(Session *); + /** + * @brief Removes a session from the pool of connected sessions. + * + * @param session Pointer to the session to remove. + */ + void remove_session_from_pool(Session *); - // TODO: Session* must be a unique_ptr or is this fine? - std::unordered_map connected_sessions; - mutable std::shared_mutex connected_sessions_lock; + /** + * @brief Checks for session takeover based on the client ID. + * + * @param client_id The ID of the session to check. + */ + void check_for_session_takeover(const std::string &); + std::unordered_map connected_sessions; /**< Map of client IDs to session pointers. */ + mutable std::shared_mutex connected_sessions_lock; /**< Mutex for thread-safe access to connected_sessions. */ }; #endif // INCLUDE_BROKER_SESSION_MANAGER_HPP_ diff --git a/src/libmqttd/exceptions.hpp b/src/libmqttd/exceptions.hpp index b954d9c..5d58184 100644 --- a/src/libmqttd/exceptions.hpp +++ b/src/libmqttd/exceptions.hpp @@ -3,14 +3,32 @@ #include +/** + * @brief Exception thrown when a function is not yet implemented. + */ class NotImplemented : public std::logic_error { public: + /** + * @brief Constructs a NotImplemented exception. + */ NotImplemented() : std::logic_error("Function not yet implemented"){}; }; +/** + * @brief Exception thrown when a received packet is malformed. + */ class MalformedPacket : public std::runtime_error { public: + /** + * @brief Constructs a MalformedPacket exception. + */ MalformedPacket() : std::runtime_error("Received a malformed packet"){}; + + /** + * @brief Constructs a MalformedPacket exception with additional information. + * + * @param info Additional information about the malformed packet. + */ MalformedPacket(std::string info) : std::runtime_error("Received a malformed packet: " + info) {} }; #endif // INCLUDE_LIBMQTTD_EXCEPTIONS_HPP_ diff --git a/src/libmqttd/network/connection/connect_ack.cpp b/src/libmqttd/network/connection/connect_ack.cpp index b6c3b90..069be59 100644 --- a/src/libmqttd/network/connection/connect_ack.cpp +++ b/src/libmqttd/network/connection/connect_ack.cpp @@ -2,21 +2,20 @@ #include "packet_interface.hpp" #include "property.hpp" #include +#include #include #include -ConnectACK::ConnectACK() : PacketInterface() { - PacketInterface::fixed_header.packet_type = PacketType::CONNACK; - PacketInterface::fixed_header.packet_flags = 0; +ConnectACK::ConnectACK() : IPacket() { + IPacket::fixed_header.packet_type = PacketType::CONNACK; + IPacket::fixed_header.packet_flags = 0; // There is a obrigatory reason code and connect acknowledge flags after fixed header, thus we are garanted to have at least 2 bytes - PacketInterface::fixed_header.remaining_length = 2; + IPacket::fixed_header.remaining_length = 2; this->reason_code = ConnectReasonCode::SUCCESS; this->session_present = false; }; -void ConnectACK::add_property(const PropertyIdentifier &prop, const PropertyValue &value) { - this->properties[prop] = value; -} +void ConnectACK::add_property(const PropertyIdentifier &prop, const PropertyValue &value) { this->properties[prop] = value; } std::vector ConnectACK::as_bytes() { std::vector variable_header_bytes; @@ -30,9 +29,9 @@ std::vector ConnectACK::as_bytes() { std::vector properties_bytes = properties.as_bytes(); variable_header_bytes.insert(variable_header_bytes.end(), properties_bytes.begin(), properties_bytes.end()); - PacketInterface::fixed_header.remaining_length = variable_header_bytes.size(); + IPacket::fixed_header.remaining_length = variable_header_bytes.size(); - std::vector fixed_header_bytes = PacketInterface::as_bytes(); + std::vector fixed_header_bytes = IPacket::as_bytes(); fixed_header_bytes.insert(fixed_header_bytes.end(), variable_header_bytes.begin(), variable_header_bytes.end()); return fixed_header_bytes; } diff --git a/src/libmqttd/network/connection/connect_ack.hpp b/src/libmqttd/network/connection/connect_ack.hpp index b3f1caa..7fe0afe 100644 --- a/src/libmqttd/network/connection/connect_ack.hpp +++ b/src/libmqttd/network/connection/connect_ack.hpp @@ -6,82 +6,82 @@ /** * @brief Enum class representing the reason codes for MQTT Connect packets according to MQTT v5.0 specification. - * + * * These reason codes are used to indicate the result of a connection attempt. * Refer to MQTT Version 5.0 topic 3.2.2.2 for more information */ enum class ConnectReasonCode : uint8_t { - SUCCESS = 0, /**< The Connection is accepted. */ - UNSPECIFIED_ERROR = 128, /**< The Server does not wish to reveal the reason for the failure, or none of the other Reason Codes apply. */ - MALFORMED_PACKET = 129, /**< Data within the CONNECT packet could not be correctly parsed. */ - PROTOCOL_ERROR = 130, /**< Data in the CONNECT packet does not conform to this specification. */ + SUCCESS = 0, /**< The Connection is accepted. */ + UNSPECIFIED_ERROR = 128, /**< The Server does not wish to reveal the reason for the failure, or none of the other Reason Codes apply. */ + MALFORMED_PACKET = 129, /**< Data within the CONNECT packet could not be correctly parsed. */ + PROTOCOL_ERROR = 130, /**< Data in the CONNECT packet does not conform to this specification. */ IMPLEMENTATION_SPECIFIC_ERROR = 131, /**< The CONNECT is valid but is not accepted by this Server. */ - UNSUPPORTED_PROTOCOL_VERSION = 132, /**< The Server does not support the version of the MQTT protocol requested by the Client. */ - CLIENT_IDENTIFIER_NOT_VALID = 133, /**< The Client Identifier is a valid string but is not allowed by the Server. */ - BAD_USERNAME_OR_PASSWORD = 134, /**< The provided username or password is not valid. */ - NOT_AUTHORIZED = 135, /**< The Client is not authorized to connect. */ - SERVER_UNAVAILABLE = 136, /**< The MQTT Server is not available. */ - SERVER_BUSY = 137, /**< The Server is busy. Try again later. */ - BANNED = 138, /**< This Client has been banned by administrative action. */ - BAD_AUTHENTICATION_METHOD = 140, /**< The authentication method is not supported or does not match the authentication method currently in use. */ - TOPIC_NAME_INVALID = 144, /**< The Will Topic Name is not malformed, but is not accepted by this Server. */ - PACKET_TOO_LARGE = 149, /**< The CONNECT packet exceeded the maximum permissible size. */ - QUOTA_EXCEEDED = 151, /**< An implementation or administrative imposed limit has been exceeded. */ - PAYLOAD_FORMAT_INVALID = 153, /**< The Will Payload does not match the specified Payload Format Indicator. */ - RETAIN_NOT_SUPPORTED = 154, /**< The Server does not support retained messages, and Will Retain was set to 1. */ - QOS_NOT_SUPPORTED = 155, /**< The Server does not support the QoS set in Will QoS. */ - USER_ANOTHER_SERVER = 156, /**< The Client should temporarily use another server. */ - SERVER_MOVED = 157, /**< The Client should permanently use another server. */ - CONNECTION_RATE_EXCEEDED = 159 /**< The connection rate limit has been exceeded. */ + UNSUPPORTED_PROTOCOL_VERSION = 132, /**< The Server does not support the version of the MQTT protocol requested by the Client. */ + CLIENT_IDENTIFIER_NOT_VALID = 133, /**< The Client Identifier is a valid string but is not allowed by the Server. */ + BAD_USERNAME_OR_PASSWORD = 134, /**< The provided username or password is not valid. */ + NOT_AUTHORIZED = 135, /**< The Client is not authorized to connect. */ + SERVER_UNAVAILABLE = 136, /**< The MQTT Server is not available. */ + SERVER_BUSY = 137, /**< The Server is busy. Try again later. */ + BANNED = 138, /**< This Client has been banned by administrative action. */ + BAD_AUTHENTICATION_METHOD = 140, /**< The authentication method is not supported or does not match the authentication method currently in use. */ + TOPIC_NAME_INVALID = 144, /**< The Will Topic Name is not malformed, but is not accepted by this Server. */ + PACKET_TOO_LARGE = 149, /**< The CONNECT packet exceeded the maximum permissible size. */ + QUOTA_EXCEEDED = 151, /**< An implementation or administrative imposed limit has been exceeded. */ + PAYLOAD_FORMAT_INVALID = 153, /**< The Will Payload does not match the specified Payload Format Indicator. */ + RETAIN_NOT_SUPPORTED = 154, /**< The Server does not support retained messages, and Will Retain was set to 1. */ + QOS_NOT_SUPPORTED = 155, /**< The Server does not support the QoS set in Will QoS. */ + USER_ANOTHER_SERVER = 156, /**< The Client should temporarily use another server. */ + SERVER_MOVED = 157, /**< The Client should permanently use another server. */ + CONNECTION_RATE_EXCEEDED = 159 /**< The connection rate limit has been exceeded. */ }; -/** +/** * @brief Connect Acknowledge packet according to MQTT Version 5.0 topic 3.2. - * + * * This class represents a Connect Acknowledge packet as defined in the MQTT Version 5.0 specification (topic 3.2). */ -class ConnectACK : public PacketInterface { +class ConnectACK : public IPacket { public: /** * @brief Constructs a new Connect ACK packet with default values. - * + * * The default values are: reason code set to SUCCESS (0x00) and session_present set to false. */ ConnectACK(); ~ConnectACK() = default; - + /** * @brief Sets the session_present value. - * + * * @param value The value to set for session_present. */ void set_session_present(const bool &value) { this->session_present = value; }; /** * @brief Sets the reason code to be returned to the client. - * + * * @param value The ConnectReasonCode to set as the reason code. */ void set_reason_code(const ConnectReasonCode &value) { this->reason_code = value; }; /** * @brief Adds a property to the property map. - * + * * @param identifier The identifier of the property to add. * @param value The value of the property to add. */ - void add_property(const PropertyIdentifier& identifier, const PropertyValue& value); + void add_property(const PropertyIdentifier &identifier, const PropertyValue &value); /** * @brief Converts the packet to bytes for transmission over a socket to the client. - * + * * @return A vector of bytes representing the packet. */ std::vector as_bytes(); private: - //Variable Header - + // Variable Header + /** * @brief Indicates whether the Server is using Session State from a previous connection for the respective ClientID. */ @@ -89,7 +89,7 @@ private: /** * @brief The reason code indicating if the connection was accepted or not. - * + * * Only ConnectReasonCode::SUCCESS indicates a successful connection. */ ConnectReasonCode reason_code; @@ -100,4 +100,4 @@ private: MQTTProperties properties; }; -#endif // INCLUDE_CONNECTION_CONNECT_ACK_HPP_ +#endif // INCLUDE_CONNECTION_CONNECT_ACK_HPP_ diff --git a/src/libmqttd/network/connection/connect_packet.cpp b/src/libmqttd/network/connection/connect_packet.cpp index 42551f8..bf45ff5 100644 --- a/src/libmqttd/network/connection/connect_packet.cpp +++ b/src/libmqttd/network/connection/connect_packet.cpp @@ -8,14 +8,14 @@ #include #include -ConnectPacket::ConnectPacket(PacketInterface &packet) : PacketInterface(packet) { +ConnectPacket::ConnectPacket(IPacket &packet) : IPacket(packet) { parse_variable_header(); parse_payload(); } ConnectPacket::~ConnectPacket() {} -ConnectPacket::ConnectPacket(std::vector data) : PacketInterface(data) { parse_variable_header(); } +ConnectPacket::ConnectPacket(std::vector data) : IPacket(data) { parse_variable_header(); } void ConnectPacket::parse_variable_header() { spdlog::trace("Parsing Connect variable header"); @@ -55,7 +55,7 @@ ConnectionFlagValue ConnectPacket::get_connection_flag(ConnectFlags flag) const std::string ConnectPacket::as_string() const { std::ostringstream packet_str; - packet_str << PacketInterface::as_string(); + packet_str << IPacket::as_string(); packet_str << "\t" << "\u21B3" << "Variable Hedaer" << std::endl; diff --git a/src/libmqttd/network/connection/connect_packet.hpp b/src/libmqttd/network/connection/connect_packet.hpp index 7da7999..b8487d0 100644 --- a/src/libmqttd/network/connection/connect_packet.hpp +++ b/src/libmqttd/network/connection/connect_packet.hpp @@ -22,9 +22,9 @@ enum ConnectFlags : uint16_t { using ConnectionFlagValue = std::variant; -class ConnectPacket : public PacketInterface { +class ConnectPacket : public IPacket { public: - ConnectPacket(PacketInterface &); + ConnectPacket(IPacket &); ConnectPacket(std::vector); ~ConnectPacket(); @@ -47,7 +47,7 @@ private: std::vector::const_iterator payload_start_byte; uint16_t packet_identifier = 0; MQTTProperties properties; - uint byte_size = 0; + uint size_in_bytes = 0; // Payload utf8_str client_id; diff --git a/src/libmqttd/network/disconnection/disconnect_packet.cpp b/src/libmqttd/network/disconnection/disconnect_packet.cpp index 1ca48b7..327d35e 100644 --- a/src/libmqttd/network/disconnection/disconnect_packet.cpp +++ b/src/libmqttd/network/disconnection/disconnect_packet.cpp @@ -6,27 +6,27 @@ #include #include -DisconnectPacket::DisconnectPacket() : PacketInterface() { - PacketInterface::fixed_header.packet_type = PacketType::DISCONNECT; +DisconnectPacket::DisconnectPacket() : IPacket() { + IPacket::fixed_header.packet_type = PacketType::DISCONNECT; // There is a obrigatory reason code - PacketInterface::fixed_header.remaining_length = 1; + IPacket::fixed_header.remaining_length = 1; this->reason_code = DisconnectReasonCode::UNSPECIFIED_ERROR; }; -DisconnectPacket::DisconnectPacket(PacketInterface &packet) : PacketInterface(packet) { +DisconnectPacket::DisconnectPacket(IPacket &packet) : IPacket(packet) { // There is a obrigatory reason code - PacketInterface::fixed_header.remaining_length = 1; + IPacket::fixed_header.remaining_length = 1; - uint8_t reason_code = utilities::types::get_fixed_size_integer(PacketInterface::variable_header_start_byte); + uint8_t reason_code = utilities::types::get_fixed_size_integer(IPacket::variable_header_start_byte); this->reason_code = DisconnectReasonCode(reason_code); - auto proprties_start_byte = std::next(PacketInterface::variable_header_start_byte); + auto proprties_start_byte = std::next(IPacket::variable_header_start_byte); this->properties = MQTTProperties(proprties_start_byte); } -DisconnectPacket::DisconnectPacket(const std::vector &data) : PacketInterface(data) { - uint8_t reason_code = utilities::types::get_fixed_size_integer(PacketInterface::variable_header_start_byte); +DisconnectPacket::DisconnectPacket(const std::vector &data) : IPacket(data) { + uint8_t reason_code = utilities::types::get_fixed_size_integer(IPacket::variable_header_start_byte); this->reason_code = DisconnectReasonCode(reason_code); - auto proprties_start_byte = std::next(PacketInterface::variable_header_start_byte); + auto proprties_start_byte = std::next(IPacket::variable_header_start_byte); this->properties = MQTTProperties(proprties_start_byte); } @@ -39,9 +39,9 @@ std::vector DisconnectPacket::as_bytes() { std::vector properties_bytes = properties.as_bytes(); variable_header_bytes.insert(variable_header_bytes.end(), properties_bytes.begin(), properties_bytes.end()); - PacketInterface::fixed_header.remaining_length = variable_header_bytes.size(); + IPacket::fixed_header.remaining_length = variable_header_bytes.size(); - std::vector fixed_header_bytes = PacketInterface::as_bytes(); + std::vector fixed_header_bytes = IPacket::as_bytes(); fixed_header_bytes.insert(fixed_header_bytes.end(), variable_header_bytes.begin(), variable_header_bytes.end()); return fixed_header_bytes; } diff --git a/src/libmqttd/network/disconnection/disconnect_packet.hpp b/src/libmqttd/network/disconnection/disconnect_packet.hpp index 202c751..0583a84 100644 --- a/src/libmqttd/network/disconnection/disconnect_packet.hpp +++ b/src/libmqttd/network/disconnection/disconnect_packet.hpp @@ -4,55 +4,94 @@ #include #include +/** + * @brief Enum representing the reason codes for disconnecting from MQTT. + */ enum class DisconnectReasonCode : uint8_t { - NORMAL_DISCONNECTION = 0, - DISCONNECT_WITH_WILL_MESSAGE = 4, - UNSPECIFIED_ERROR = 128, - MALFORMED_PACKET = 129, - PROTOCOL_ERROR = 130, - IMPLEMENTATION_SPECIFIC_ERROR = 131, - NOT_AUTHORIZED = 135, - SERVER_BUSY = 137, - SERVER_SHUTING_DOWN = 139, - KEEPALIVE_TIMEOUT = 141, - SESSION_TAKEN_OVER = 142, - TOPIC_FILTER_INVALID = 143, - TOPIC_NAME_INVALID = 144, - RECEIVE_MAXIMUM_EXCEEDED = 147, - TOPIC_ALIAS_INVALID = 148, - PACKET_TOO_LARGE = 149, - MESSAGE_RATE_TOO_HIGH = 150, - QUOTA_EXCEEDED = 151, - ADMINISTRATIVE_ACTION = 152, - PAYLOAD_FORMAT_INVALID = 153, - RETAIN_NOT_SUPPORTED = 154, - QOS_NOT_SUPPORTED = 155, - USER_ANOTHER_SERVER = 156, - SERVER_MOVED = 157, - SHARED_SUBSCRIPTION_NOT_SUPPORTED = 158, - CONNECTION_RATE_EXCEEDED = 159, - MAXIMUM_CONNECT_TIMEOUT = 160, - SUBSCRIPTIONS_IDENTIFIERS_NOT_SUPPORTED = 161, - WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162, + NORMAL_DISCONNECTION = 0, /**< Close the connection normally. Do not send the Will Message. */ + DISCONNECT_WITH_WILL_MESSAGE = 4, /**< The Client wishes to disconnect but requires that the Server also publishes its Will Message. */ + UNSPECIFIED_ERROR = 128, /**< The Connection is closed but the sender either does not wish to reveal the reason, or none of the other Reason Codes apply. */ + MALFORMED_PACKET = 129, /**< The received packet does not conform to this specification. */ + PROTOCOL_ERROR = 130, /**< An unexpected or out of order packet was received. */ + IMPLEMENTATION_SPECIFIC_ERROR = 131, /**< The packet received is valid but cannot be processed by this implementation. */ + NOT_AUTHORIZED = 135, /**< The request is not authorized. */ + SERVER_BUSY = 137, /**< The Server is busy and cannot continue processing requests from this Client. */ + SERVER_SHUTING_DOWN = 139, /**< The Server is shutting down. */ + KEEPALIVE_TIMEOUT = 141, /**< The Connection is closed because no packet has been received for 1.5 times the Keepalive time. */ + SESSION_TAKEN_OVER = 142, /**< Another Connection using the same ClientID has connected causing this Connection to be closed. */ + TOPIC_FILTER_INVALID = 143, /**< The Topic Filter is correctly formed, but is not accepted by this Sever. */ + TOPIC_NAME_INVALID = 144, /**< The Topic Name is correctly formed, but is not accepted by this Client or Server. */ + RECEIVE_MAXIMUM_EXCEEDED = 147, /**< The Client or Server has received more than Receive Maximum publication for which it has not sent PUBACK or PUBCOMP. */ + TOPIC_ALIAS_INVALID = 148, /**< The Client or Server has received a PUBLISH packet containing a Topic Alias which is greater than the Maximum Topic Alias it sent in the CONNECT or CONNACK packet. */ + PACKET_TOO_LARGE = 149, /**< The packet size is greater than Maximum Packet Size for this Client or Server. */ + MESSAGE_RATE_TOO_HIGH = 150, /**< Message rate too high. */ + QUOTA_EXCEEDED = 151, /**< An implementation or administrative imposed limit has been exceeded. */ + ADMINISTRATIVE_ACTION = 152, /**< The Connection is closed due to an administrative action. */ + PAYLOAD_FORMAT_INVALID = 153, /**< The payload format does not match the one specified by the Payload Format Indicator. */ + RETAIN_NOT_SUPPORTED = 154, /**< The Server has does not support retained messages. */ + QOS_NOT_SUPPORTED = 155, /**< The Client specified a QoS greater than the QoS specified in a Maximum QoS in the CONNACK. */ + USER_ANOTHER_SERVER = 156, /**< The Client should temporarily change its Server. */ + SERVER_MOVED = 157, /**< The Server is moved and the Client should permanently change its server location. */ + SHARED_SUBSCRIPTION_NOT_SUPPORTED = 158, /**< The Server does not support Shared Subscriptions. */ + CONNECTION_RATE_EXCEEDED = 159, /**< This connection is closed because the connection rate is too high. */ + MAXIMUM_CONNECT_TIMEOUT = 160, /**< This connection is closed because the connection rate is too high. */ + SUBSCRIPTIONS_IDENTIFIERS_NOT_SUPPORTED = 161, /**< The Server does not support Subscription Identifiers; the subscription is not accepted. */ + WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 162, /**< The Server does not support Wildcard Subscriptions; the subscription is not accepted. */ }; -std::ostream& operator<<(std::ostream& os, DisconnectReasonCode code); +/** + * @brief Overload of the output operator to print the DisconnectReasonCode. + */ +std::ostream &operator<<(std::ostream &os, DisconnectReasonCode code); -class DisconnectPacket : public PacketInterface { +/** + * @brief Class representing a Disconnect Packet in MQTT communication. + */ +class DisconnectPacket : public IPacket { public: + /** + * @brief Default constructor. + */ DisconnectPacket(); - DisconnectPacket(PacketInterface &); + + /** + * @brief Copy constructor. + * + * @param other The DisconnectPacket object to copy. + */ + DisconnectPacket(IPacket &other); + + /** + * @brief Constructs a DisconnectPacket object from byte vector data. + * + * @param data The byte vector containing the packet data. + */ DisconnectPacket(const std::vector &data); + + /** + * @brief Destructor. + */ ~DisconnectPacket() = default; + /** + * @brief Adds a property to the Disconnect Packet. + * + * @param prop The property identifier. + * @param value The property value. + */ void add_property(const PropertyIdentifier &prop, const PropertyValue &value); - DisconnectReasonCode reason_code; + + DisconnectReasonCode reason_code; /**< The reason code for disconnecting. */ + + /** + * @brief Converts the Disconnect Packet to a byte vector. + * + * @return The byte vector representation of the Disconnect Packet. + */ std::vector as_bytes(); - private: - // Variable Header - MQTTProperties properties; + MQTTProperties properties; /**< The properties of the Disconnect Packet. */ }; #endif // INCLUDE_DISCONNECTION_DISCONNECT_PACKET_HPP_ diff --git a/src/libmqttd/network/packet_interface/fixed_header.hpp b/src/libmqttd/network/packet_interface/fixed_header.hpp index 4623d52..327ae69 100644 --- a/src/libmqttd/network/packet_interface/fixed_header.hpp +++ b/src/libmqttd/network/packet_interface/fixed_header.hpp @@ -5,33 +5,41 @@ #include #include - +/** + * @brief Enumeration of MQTT packet types. + */ enum class PacketType : uint8_t { - RESERVED = 0, - CONNECT = 1, - CONNACK = 2, - PUBLISH = 3, - PUBACK = 4, - PUBREC = 5, - PUBREL = 6, - PUBCOMP = 7, - SUBSCRIBE = 8, - SUBACK = 9, - UNSUBSCRIBE = 10, - UNSUBACK = 11, - PINGREQ = 12, - PINGRESP = 13, - DISCONNECT = 14, - AUTH = 15, - UNSET=99, + RESERVED = 0, /**< Reserved. */ + CONNECT = 1, /**< CONNECT: Client request to connect to Server. */ + CONNACK = 2, /**< CONNACK: Connect acknowledgment. */ + PUBLISH = 3, /**< PUBLISH: Publish message. */ + PUBACK = 4, /**< PUBACK: Publish acknowledgment. */ + PUBREC = 5, /**< PUBREC: Publish received (assured delivery part 1). */ + PUBREL = 6, /**< PUBREL: Publish release (assured delivery part 2). */ + PUBCOMP = 7, /**< PUBCOMP: Publish complete (assured delivery part 3). */ + SUBSCRIBE = 8, /**< SUBSCRIBE: Client subscribe request. */ + SUBACK = 9, /**< SUBACK: Subscribe acknowledgment. */ + UNSUBSCRIBE = 10, /**< UNSUBSCRIBE: Unsubscribe request. */ + UNSUBACK = 11, /**< UNSUBACK: Unsubscribe acknowledgment. */ + PINGREQ = 12, /**< PINGREQ: PING request. */ + PINGRESP = 13, /**< PINGRESP: PING response. */ + DISCONNECT = 14, /**< DISCONNECT: Client is disconnecting. */ + AUTH = 15, /**< AUTH: Authentication exchange. */ + UNSET = 99, /**< Unset or unknown type. */ }; -std::ostream& operator<<(std::ostream& lhs, PacketType p); +/** + * @brief Overload of the output operator to print the packet type. + */ +std::ostream &operator<<(std::ostream &lhs, PacketType p); +/** + * @brief Structure representing the fixed header of an MQTT packet. + */ struct FixedHeader { - PacketType packet_type = PacketType(0); - std::bitset<4> packet_flags = {0}; - int_vb remaining_length = int_vb(0); + PacketType packet_type = PacketType(0); /**< Packet type. */ + std::bitset<4> packet_flags = {0}; /**< Packet flags. */ + int_vb remaining_length = int_vb(0); /**< Remaining length. */ }; #endif // INCLUDE_PACKET_INTERFACE_FIXED_HEADER_HPP_ diff --git a/src/libmqttd/network/packet_interface/packet_interface.cpp b/src/libmqttd/network/packet_interface/packet_interface.cpp index aa33105..6e20d81 100644 --- a/src/libmqttd/network/packet_interface/packet_interface.cpp +++ b/src/libmqttd/network/packet_interface/packet_interface.cpp @@ -3,13 +3,13 @@ #include #include -PacketInterface::PacketInterface() { +IPacket::IPacket() { this->raw_data = {}; this->fixed_header.packet_type = PacketType::UNSET; this->fixed_header.remaining_length = 0; } -PacketInterface::PacketInterface(const std::vector &data) { +IPacket::IPacket(const std::vector &data) { this->raw_data = data; unsigned char fixed_header_packet_type = (static_cast(raw_data[0]) >> 4) & 0x0F; this->fixed_header.packet_type = PacketType(fixed_header_packet_type); @@ -22,7 +22,7 @@ PacketInterface::PacketInterface(const std::vector &data) { this->variable_header_start_byte = std::next(raw_data.begin(), fixed_header.remaining_length.size() + 1); } -PacketInterface::PacketInterface(const PacketInterface &packet) { +IPacket::IPacket(const IPacket &packet) { this->fixed_header.packet_type = packet.fixed_header.packet_type; this->fixed_header.packet_flags = packet.fixed_header.packet_flags; this->fixed_header.remaining_length = packet.fixed_header.remaining_length; @@ -31,7 +31,7 @@ PacketInterface::PacketInterface(const PacketInterface &packet) { this->raw_data = packet.raw_data; } -std::string PacketInterface::as_string() const { +std::string IPacket::as_string() const { std::ostringstream packet_str; packet_str << std::endl; packet_str << "Packet Type = " << this->get_packet_type() << std::endl; @@ -45,7 +45,7 @@ std::string PacketInterface::as_string() const { return packet_str.str(); } -std::vector PacketInterface::as_bytes() { +std::vector IPacket::as_bytes() { std::vector packet_bytes; uint8_t flags_value = static_cast(fixed_header.packet_flags.to_ulong()); diff --git a/src/libmqttd/network/packet_interface/packet_interface.hpp b/src/libmqttd/network/packet_interface/packet_interface.hpp index 6f0bf66..02ea3c4 100644 --- a/src/libmqttd/network/packet_interface/packet_interface.hpp +++ b/src/libmqttd/network/packet_interface/packet_interface.hpp @@ -8,30 +8,87 @@ #include #include -class PacketInterface { +/** + * @brief Interface class for network control packets. + * + * This class serves as an interface for network control packets in MQTT communication. + */ +class IPacket { public: - PacketInterface(const std::vector &); - PacketInterface(const PacketInterface &); - PacketInterface(); - virtual ~PacketInterface() = default; + /** + * @brief Constructs a new IPacket object from a byte vector. + * + * @param data The byte vector containing the packet data. + */ + IPacket(const std::vector &data); + /** + * @brief Copy constructor. + * + * @param other The IPacket object to copy. + */ + IPacket(const IPacket &other); + + /** + * @brief Default constructor. + */ + IPacket(); + + /** + * @brief Virtual destructor. + */ + virtual ~IPacket() = default; + + /** + * @brief Gets the length of the packet. + * + * @return The length of the packet in bytes. + */ inline uint length() const { return sizeof(this->fixed_header) + this->fixed_header.remaining_length; } + /** + * @brief Gets the packet type. + * + * @return The packet type. + */ inline PacketType get_packet_type() const { return this->fixed_header.packet_type; }; + + /** + * @brief Gets the packet flags. + * + * @return The packet flags. + */ inline std::bitset<4> get_packet_flags() const { return this->fixed_header.packet_flags; }; + /** + * @brief Converts the packet to a string representation. + * + * @return The string representation of the packet. + */ virtual std::string as_string() const; + + /** + * @brief Converts the packet to a byte vector. + * + * @return The byte vector representation of the packet. + */ virtual std::vector as_bytes(); protected: + std::vector raw_data; /**< The raw data of the packet. */ + FixedHeader fixed_header; /**< The fixed header of the packet. */ - std::vector raw_data; - FixedHeader fixed_header; - + /** + * @brief Parses the variable header of the packet. + */ virtual void parse_variable_header() { throw NotImplemented(); }; + + /** + * @brief Parses the payload of the packet. + */ virtual void parse_payload() { throw NotImplemented(); }; - std::vector::const_iterator variable_header_start_byte; + std::vector::const_iterator variable_header_start_byte; /**< Iterator pointing to the start of the variable header. */ }; #endif // INCLUDE_NETWORK_CONTROL_PACKET_HPP_ diff --git a/src/libmqttd/network/packet_interface/property.hpp b/src/libmqttd/network/packet_interface/property.hpp index 46a6131..af1b951 100644 --- a/src/libmqttd/network/packet_interface/property.hpp +++ b/src/libmqttd/network/packet_interface/property.hpp @@ -14,63 +14,106 @@ #include #include +/** + * @brief Enumeration of MQTT Control Packet Property Identifiers. + */ enum class PropertyIdentifier : uint32_t { - PAYLOAD_FORMAT_INDICATOR = 1, - MESSAGE_EXPIRY_INTERVAL = 2, - CONTENT_TYPE = 3, - RESPONSE_TOPIC = 8, - CORRELATION_DATA = 9, - SUBSCRIPTION_IDENTIFIER = 11, - SESSION_EXPIRY_INTERVAL = 17, - ASSIGNED_CLIENT_IDENTIFIER = 18, - SERVER_KEEP_ALIVE = 19, - AUTHENTICATION_METHOD = 21, - AUTHENTICATION_DATA = 22, - REQUEST_PROBLEM_INFORMATION = 23, - WILL_DELAY_INTERVAL = 24, - REQUEST_RESPONSE_INFORMATION = 25, - RESPONSE_INFORMATION = 26, - SERVER_REFERENCE = 28, - REASON_STRING = 31, - RECEIVE_MAXIMUM = 33, - TOPIC_ALIAS_MAXIMUM = 34, - TOPIC_ALIAS = 35, - MAXIMUM_QOS = 36, - RETAIN_AVAILABLE = 37, - USER_PROPERTY = 38, - MAXIMUM_PACKET_SIZE = 39, - WILDCARD_SUBSCRIPTION_AVAILABLE = 40, - SUBSCRIPTION_IDENTIFIER_AVAILABLE = 41, - SHARED_SUBSCRIPTION_AVAILABLE = 42 + PAYLOAD_FORMAT_INDICATOR = 1, /**< Payload Format Indicator. */ + MESSAGE_EXPIRY_INTERVAL = 2, /**< Message Expiry Interval. */ + CONTENT_TYPE = 3, /**< Content Type. */ + RESPONSE_TOPIC = 8, /**< Response Topic. */ + CORRELATION_DATA = 9, /**< Correlation Data. */ + SUBSCRIPTION_IDENTIFIER = 11, /**< Subscription Identifier. */ + SESSION_EXPIRY_INTERVAL = 17, /**< Session Expiry Interval. */ + ASSIGNED_CLIENT_IDENTIFIER = 18, /**< Assigned Client Identifier. */ + SERVER_KEEP_ALIVE = 19, /**< Server Keep Alive. */ + AUTHENTICATION_METHOD = 21, /**< Authentication Method. */ + AUTHENTICATION_DATA = 22, /**< Authentication Data. */ + REQUEST_PROBLEM_INFORMATION = 23, /**< Request Problem Information. */ + WILL_DELAY_INTERVAL = 24, /**< Will Delay Interval. */ + REQUEST_RESPONSE_INFORMATION = 25, /**< Request Response Information. */ + RESPONSE_INFORMATION = 26, /**< Response Information. */ + SERVER_REFERENCE = 28, /**< Server Reference. */ + REASON_STRING = 31, /**< Reason String. */ + RECEIVE_MAXIMUM = 33, /**< Receive Maximum. */ + TOPIC_ALIAS_MAXIMUM = 34, /**< Topic Alias Maximum. */ + TOPIC_ALIAS = 35, /**< Topic Alias. */ + MAXIMUM_QOS = 36, /**< Maximum QoS. */ + RETAIN_AVAILABLE = 37, /**< Retain Available. */ + USER_PROPERTY = 38, /**< User Property. */ + MAXIMUM_PACKET_SIZE = 39, /**< Maximum Packet Size. */ + WILDCARD_SUBSCRIPTION_AVAILABLE = 40, /**< Wildcard Subscription Available. */ + SUBSCRIPTION_IDENTIFIER_AVAILABLE = 41, /**< Subscription Identifier Available. */ + SHARED_SUBSCRIPTION_AVAILABLE = 42 /**< Shared Subscription Available. */ }; -using UserProperty = std::queue; -using PropertyValue = std::variant; -using PropertyMap = std::map; +using UserProperty = std::queue; /**< User Property type definition. */ +using PropertyValue = std::variant; /**< Property Value type definition. */ +using PropertyMap = std::map; /**< Property Map type definition. */ std::ostream &operator<<(std::ostream &os, const UserProperty &value); std::ostream &operator<<(std::ostream &os, const PropertyIdentifier &value); std::ostream &operator<<(std::ostream &os, const PropertyValue &value); std::ostream &operator<<(std::ostream &os, const PropertyMap &value); +/** + * @brief Class representing MQTT Control Packet Properties. + */ class MQTTProperties { public: + /** + * @brief Default constructor. + */ MQTTProperties(); + + /** + * @brief Constructs MQTTProperties from a byte vector. + * + * @param property_start Iterator pointing to the start of the property data in the byte vector. + */ MQTTProperties(const std::vector::const_iterator &property_start); + + /** + * @brief Destructor. + */ ~MQTTProperties() = default; + /** + * @brief Converts MQTTProperties to a byte vector. + * + * @return Byte vector representation of MQTTProperties. + */ std::vector as_bytes() const; + /** + * @brief Gets the size of MQTTProperties. + * + * @return The size of MQTTProperties. + */ uint16_t size() const { return this->length; }; + + /** + * @brief Gets the property value for the specified property identifier. + * + * @param prop The property identifier. + * @return The property value. + */ PropertyValue get_property(const PropertyIdentifier &prop) { return this->properties[prop]; }; + /** + * @brief Overloads the subscript operator to access properties by identifier. + * + * @param prop The property identifier. + * @return The property value. + */ + PropertyValue &operator[](PropertyIdentifier prop); + friend std::ostream &operator<<(std::ostream &os, const std::byte &value); friend std::ostream &operator<<(std::ostream &os, const MQTTProperties &value); - PropertyValue &operator[](PropertyIdentifier); private: - int_vb length; - PropertyMap properties; + int_vb length; /**< Length of the properties. */ + PropertyMap properties; /**< Map containing MQTT properties. */ }; #endif // INCLUDE_CONTROL_PACKET_PROPERTY_HPP_ diff --git a/src/libmqttd/protocol/session/session.cpp b/src/libmqttd/protocol/session/session.cpp index 0058ef9..569e909 100644 --- a/src/libmqttd/protocol/session/session.cpp +++ b/src/libmqttd/protocol/session/session.cpp @@ -44,7 +44,6 @@ void Session::close() { this->is_session_alive = false; if (this->keepalive_thread.joinable()) this->keepalive_thread.join(); - } std::size_t Session::send(const std::vector &buffer) { @@ -70,8 +69,7 @@ void Session::close_if_not_connected(uint timeout_sec) { return; std::ostringstream log_msg; - log_msg << "Session timed out while waiting for CONENCT packet" - << " (timeout is " << timeout_sec << " seconds)"; + log_msg << "Session timed out while waiting for CONNECT packet (timeout is " << timeout_sec << " seconds)"; spdlog::warn(log_msg.str()); this->close(DisconnectReasonCode::MAXIMUM_CONNECT_TIMEOUT); } @@ -104,7 +102,7 @@ void Session::listen() { return; } - this->current_packet = new PacketInterface(buffer); + this->current_packet = new IPacket(buffer); switch (this->current_packet->get_packet_type()) { case PacketType::CONNECT: { this->set_state(StateConnect::get_instance()); diff --git a/src/libmqttd/protocol/session/session.hpp b/src/libmqttd/protocol/session/session.hpp index 2c3ac65..cc9f218 100644 --- a/src/libmqttd/protocol/session/session.hpp +++ b/src/libmqttd/protocol/session/session.hpp @@ -16,49 +16,120 @@ class ISessionState; #include -const unsigned int buffer_size = 2048; - +/** + * @brief Class representing a session in the MQTT protocol. + * + * This class manages the communication session with an MQTT client. + */ class Session { public: + /** + * @brief Default constructor. + */ Session(); + + /** + * @brief Constructor initializing the session with a socket file descriptor. + * + * @param socket_fd The socket file descriptor. + */ Session(int socket_fd); + + /** + * @brief Destructor. + */ ~Session(); - std::string client_id; + std::string client_id; /**< The client ID associated with the session. */ + /** + * @brief Starts listening for incoming data on the session socket. + */ void listen(); + + /** + * @brief Closes the session. + */ void close(); - void close(const DisconnectReasonCode &); - void set_state(ISessionState &); + + /** + * @brief Closes the session with a specific reason code. + * + * @param reason_code The reason code for disconnection. + */ + void close(const DisconnectReasonCode &reason_code); + + /** + * @brief Sets the current state of the session. + * + * @param state The state to set. + */ + void set_state(ISessionState &state); + + /** + * @brief Checks if the session is alive. + * + * @return True if the session is alive, false otherwise. + */ inline bool is_alive() const { return this->is_session_alive; }; + + /** + * @brief Checks if the session is connected. + * + * @return True if the session is connected, false otherwise. + */ inline bool is_connected() const { return this->is_session_connected; }; - inline PacketInterface *get_current_packet() const { return this->current_packet; }; + + /** + * @brief Gets the current packet being processed by the session. + * + * @return A pointer to the current packet. + */ + inline IPacket *get_current_packet() const { return this->current_packet; }; + + /** + * @brief Gets the current state of the session. + * + * @return A pointer to the current state. + */ inline ISessionState *get_current_state() const { return this->current_state; }; - std::size_t send(const std::vector &); + /** + * @brief Sends data over the session socket. + * + * @param buffer The data to send. + * @return The number of bytes sent. + */ + std::size_t send(const std::vector &buffer); - std::function on_connect; - std::function on_disconnect; + std::function on_connect; /**< Callback function invoked when a client connects. */ + std::function on_disconnect; /**< Callback function invoked when a client disconnects. */ protected: friend class StateConnect; friend class StateDisconnect; - std::atomic is_session_alive; - std::atomic is_session_connected; + std::atomic is_session_alive; /**< Flag indicating if the session is alive. */ + std::atomic is_session_connected; /**< Flag indicating if the session is connected. */ private: - ISessionState *current_state; - PacketInterface *current_packet; - - int socket; - std::thread keepalive_thread; + ISessionState *current_state; /**< Pointer to the current session state. */ + IPacket *current_packet; /**< Pointer to the current packet being processed. */ + + int socket; /**< Socket file descriptor for the session. */ + std::thread keepalive_thread; /**< Thread for handling keepalive messages. */ + const unsigned int buffer_size = 65535; /**< Max TCP packet bytes accepted in a single receive call. */ + + /** + * @brief Joins the keepalive thread. + */ void join(); + /** + * @brief Closes the session if it's not connected within a timeout period. + * + * @param timeout_sec Timeout period in seconds. + */ void close_if_not_connected(uint timeout_sec = 10); - - - time_t last_keepalive; }; - #endif // INCLUDE_PROTOCOL_SESSION_HPP_ diff --git a/src/libmqttd/protocol/session/states/state_connect.cpp b/src/libmqttd/protocol/session/states/state_connect.cpp index 4de220b..028f4b4 100644 --- a/src/libmqttd/protocol/session/states/state_connect.cpp +++ b/src/libmqttd/protocol/session/states/state_connect.cpp @@ -35,7 +35,7 @@ void StateConnect::process(Session *session) { ConnectACK ack_packet; ack_packet.set_session_present(false); try { - PacketInterface *packet_interface = session->get_current_packet(); + IPacket *packet_interface = session->get_current_packet(); ConnectPacket packet(*packet_interface); // TODO: Validate and auth packet diff --git a/src/libmqttd/protocol/session/states/state_connect.hpp b/src/libmqttd/protocol/session/states/state_connect.hpp index 945ec04..98f36ba 100644 --- a/src/libmqttd/protocol/session/states/state_connect.hpp +++ b/src/libmqttd/protocol/session/states/state_connect.hpp @@ -3,17 +3,49 @@ #include "state_interface.hpp" +/** + * @brief Class representing the state of establishing a connection in the MQTT protocol. + * + * This class defines the behavior and transitions associated with the connection state of a session. + */ class StateConnect : public ISessionState { public: + /** + * @brief Method called when entering the connection state. + * + * @param session Pointer to the session associated with the state. + */ void enter(Session *session) final; + + /** + * @brief Method called to process the session in the connection state. + * + * @param session Pointer to the session associated with the state. + */ void process(Session *session) final; + + /** + * @brief Method called when exiting the connection state. + * + * @param session Pointer to the session associated with the state. + */ void exit(Session *session) final; + + /** + * @brief Get the singleton instance of the connection state. + * + * @return Reference to the singleton instance of the connection state. + */ static ISessionState &get_instance(); private: - StateConnect() {}; - StateConnect(const StateConnect &); - StateConnect &operator=(const StateConnect &); + /** + * @brief Private constructor to prevent external instantiation. + */ + StateConnect(){}; + + StateConnect(const StateConnect &); /**< Copy constructor. */ + StateConnect &operator=(const StateConnect &); /**< Assignment operator. */ }; #endif // INCLUDE_FTM_STATE_CONNECT_HPP_ diff --git a/src/libmqttd/protocol/session/states/state_disconnect.cpp b/src/libmqttd/protocol/session/states/state_disconnect.cpp index 8ba90b8..564fa41 100644 --- a/src/libmqttd/protocol/session/states/state_disconnect.cpp +++ b/src/libmqttd/protocol/session/states/state_disconnect.cpp @@ -22,7 +22,7 @@ void StateDisconnect::exit(Session *session) { } void StateDisconnect::process(Session *session) { - PacketInterface *packet_interface = session->get_current_packet(); + IPacket *packet_interface = session->get_current_packet(); DisconnectPacket disconnect_packet(*packet_interface); std::ostringstream log_msg; diff --git a/src/libmqttd/protocol/session/states/state_disconnect.hpp b/src/libmqttd/protocol/session/states/state_disconnect.hpp index e75d712..b9e54a4 100644 --- a/src/libmqttd/protocol/session/states/state_disconnect.hpp +++ b/src/libmqttd/protocol/session/states/state_disconnect.hpp @@ -3,18 +3,49 @@ #include "state_interface.hpp" +/** + * @brief Class representing the state of disconnecting in the MQTT protocol. + * + * This class defines the behavior and transitions associated with the disconnect state of a session. + */ class StateDisconnect : public ISessionState { public: + /** + * @brief Method called when entering the disconnect state. + * + * @param session Pointer to the session associated with the state. + */ void enter(Session *session) final; + + /** + * @brief Method called to process the session in the disconnect state. + * + * @param session Pointer to the session associated with the state. + */ void process(Session *session) final; + + /** + * @brief Method called when exiting the disconnect state. + * + * @param session Pointer to the session associated with the state. + */ void exit(Session *session) final; + + /** + * @brief Get the singleton instance of the disconnect state. + * + * @return Reference to the singleton instance of the disconnect state. + */ static ISessionState &get_instance(); private: - StateDisconnect() {}; - StateDisconnect(const StateDisconnect &); - StateDisconnect &operator=(const StateDisconnect &); + /** + * @brief Private constructor to prevent external instantiation. + */ + StateDisconnect(){}; + + StateDisconnect(const StateDisconnect &); /**< Copy constructor. */ + StateDisconnect &operator=(const StateDisconnect &); /**< Assignment operator. */ }; - -#endif // INCLUDE_STATES_STATE_DISCONNECT_HPP_ +#endif // INCLUDE_STATES_STATE_DISCONNECT_HPP_ diff --git a/src/libmqttd/protocol/session/states/state_interface.hpp b/src/libmqttd/protocol/session/states/state_interface.hpp index 2512d2b..cfbbb14 100644 --- a/src/libmqttd/protocol/session/states/state_interface.hpp +++ b/src/libmqttd/protocol/session/states/state_interface.hpp @@ -5,17 +5,44 @@ // Forward declaration to resolve circular dependency class Session; + #include +/** + * @brief Interface class for defining session states in the MQTT protocol. + * + * This class serves as an interface for defining different states of a session in the MQTT protocol. + */ class ISessionState { public: + /** + * @brief Virtual destructor. + */ virtual ~ISessionState(){}; - virtual void enter(Session *) = 0; - virtual void process(Session *) = 0; - virtual void exit(Session *) = 0; + + /** + * @brief Method called when entering the state. + * + * @param session Pointer to the session associated with the state. + */ + virtual void enter(Session * session) = 0; + + /** + * @brief Method called to process the session in the state. + * + * @param session Pointer to the session associated with the state. + */ + virtual void process(Session * session) = 0; + + /** + * @brief Method called when exiting the state. + * + * @param session Pointer to the session associated with the state. + */ + virtual void exit(Session * session) = 0; private: - PacketInterface packet; + IPacket packet; /**< Packet associated with the state. */ }; #endif // INCLUDE_FTM_STATE_INTERFACE_HPP_ diff --git a/src/libmqttd/protocol/session/states/state_waiting_connection.hpp b/src/libmqttd/protocol/session/states/state_waiting_connection.hpp index 7ca087d..113e892 100644 --- a/src/libmqttd/protocol/session/states/state_waiting_connection.hpp +++ b/src/libmqttd/protocol/session/states/state_waiting_connection.hpp @@ -3,19 +3,49 @@ #include "state_interface.hpp" +/** + * @brief Class representing the state of waiting for a connection in the MQTT protocol. + * + * This class defines the behavior and transitions associated with the state of waiting for a connection in a session. + */ class StateWaitingConnection : public ISessionState { public: + /** + * @brief Method called when entering the state of waiting for a connection. + * + * @param session Pointer to the session associated with the state. + */ void enter(Session *session) final; + + /** + * @brief Method called to process the session in the state of waiting for a connection. + * + * @param session Pointer to the session associated with the state. + */ void process(Session *session) final; + + /** + * @brief Method called when exiting the state of waiting for a connection. + * + * @param session Pointer to the session associated with the state. + */ void exit(Session *session) final; + + /** + * @brief Get the singleton instance of the state of waiting for a connection. + * + * @return Reference to the singleton instance of the state of waiting for a connection. + */ static ISessionState &get_instance(); private: + /** + * @brief Private constructor to prevent external instantiation. + */ StateWaitingConnection() {}; - StateWaitingConnection(const StateWaitingConnection &); - StateWaitingConnection &operator=(const StateWaitingConnection &); + StateWaitingConnection(const StateWaitingConnection &); /**< Copy constructor. */ + StateWaitingConnection &operator=(const StateWaitingConnection &); /**< Assignment operator. */ }; - #endif // INCLUDE_STATES_STATE_WAITING_CONNECTION_HPP_ diff --git a/src/libmqttd/types/binary_data.hpp b/src/libmqttd/types/binary_data.hpp index 4253b25..2a9e837 100644 --- a/src/libmqttd/types/binary_data.hpp +++ b/src/libmqttd/types/binary_data.hpp @@ -1,29 +1,67 @@ #ifndef INCLUDE_TYPES_BINARY_DATA_HPP_ #define INCLUDE_TYPES_BINARY_DATA_HPP_ -#include #include #include +#include #include +/** + * @brief Class representing binary data. + * + * This class provides functionality to work with binary data, including conversion to string and byte vector. + */ class BinaryData : public TypeInterface { public: - // Create a BinaryData from the start of byte vector + /** + * @brief Default constructor. + * + * Constructs an empty BinaryData object. + */ BinaryData(); + + /** + * @brief Constructor to create BinaryData from a byte vector iterator. + * + * Constructs a BinaryData object from the provided byte vector iterator. + * + * @param data_begin Iterator pointing to the beginning of the byte vector. + */ BinaryData(const std::vector::const_iterator &data_begin); + + /** + * @brief Destructor. + */ ~BinaryData() = default; - friend std::ostream &operator<<(std::ostream &, const BinaryData&); - + /** + * @brief Get the size of the binary data. + * + * @return The size of the binary data in bytes. + */ uint16_t size() const final { return data_size; }; + + /** + * @brief Convert the binary data to a string representation. + * + * @return A string representing the binary data in hexadecimal. + */ std::string as_string() const final; + + /** + * @brief Convert the binary data to a byte vector. + * + * @return A byte vector representing the binary data. + */ std::vector as_bytes() const final; + friend std::ostream &operator<<(std::ostream &, const BinaryData &); + protected: - std::vector data; - uint16_t data_size; + std::vector data; /**< The binary data. */ + uint16_t data_size; /**< The size of the binary data in bytes. */ }; using binary_data = BinaryData; -#endif // INCLUDE_TYPES_BINARY_DATA_HPP_ +#endif // INCLUDE_TYPES_BINARY_DATA_HPP_ diff --git a/src/libmqttd/types/type_interface.hpp b/src/libmqttd/types/type_interface.hpp index 8fb4726..3030d1a 100644 --- a/src/libmqttd/types/type_interface.hpp +++ b/src/libmqttd/types/type_interface.hpp @@ -5,12 +5,37 @@ #include #include +/** + * @brief Interface class for types. + * + * This class serves as an interface for various types, providing common functionality such as size retrieval and conversion to string and byte vector. + */ class TypeInterface { public: + /** + * @brief Virtual destructor. + */ virtual ~TypeInterface() = default; - + + /** + * @brief Get the size of the type. + * + * @return The size of the type in bytes. + */ virtual uint16_t size() const = 0; + + /** + * @brief Convert the type to a string representation. + * + * @return A string representing the type. + */ virtual std::string as_string() const = 0; + + /** + * @brief Convert the type to a byte vector. + * + * @return A byte vector representing the type. + */ virtual std::vector as_bytes() const = 0; }; diff --git a/src/libmqttd/types/utf8_string.hpp b/src/libmqttd/types/utf8_string.hpp index 6f4c86e..e784da1 100644 --- a/src/libmqttd/types/utf8_string.hpp +++ b/src/libmqttd/types/utf8_string.hpp @@ -1,27 +1,70 @@ #ifndef INCLUDE_TYPES_UTF8_STRING_HPP_ #define INCLUDE_TYPES_UTF8_STRING_HPP_ -#include -#include #include +#include #include +#include #include +/** + * @brief Class representing a UTF-8 string. + * + * This class provides functionality to work with UTF-8 encoded strings, including conversion to byte vector and string representation. + */ class UTF8String : public TypeInterface { public: + /** + * @brief Default constructor. + */ UTF8String(); + + /** + * @brief Constructor that initializes the UTF-8 string from a byte vector. + * + * @param data_begin Iterator pointing to the start of the byte vector containing the UTF-8 string data. + */ UTF8String(const std::vector::const_iterator &data_begin); + + /** + * @brief Virtual destructor. + */ ~UTF8String() = default; - + + /** + * @brief Get the size of the UTF-8 string. + * + * @return The char count of the UTF-8 string. + */ uint16_t size() const final { return static_cast(utf8_string.size()); }; + + /** + * @brief Convert the UTF-8 string to a string representation. + * + * @return A string representing the UTF-8 string. + */ std::string as_string() const final { return this->utf8_string; }; + + /** + * @brief Convert the UTF-8 string to a byte vector. + * + * @return A byte vector representing the UTF-8 string. + */ std::vector as_bytes() const final; + /** + * @brief Overloaded output stream operator for UTF8String. + * + * @param os The output stream. + * @param value The UTF8String object. + * @return The output stream. + */ friend std::ostream &operator<<(std::ostream &os, const UTF8String &value); protected: - std::string utf8_string; + std::string utf8_string; /**< The UTF-8 string. */ }; using utf8_str = UTF8String; + #endif // INCLUDE_TYPES_UTF8_STRING_HPP_ diff --git a/src/libmqttd/types/utf8_string_pair.hpp b/src/libmqttd/types/utf8_string_pair.hpp index a5a8733..f8c7062 100644 --- a/src/libmqttd/types/utf8_string_pair.hpp +++ b/src/libmqttd/types/utf8_string_pair.hpp @@ -4,23 +4,70 @@ #include #include +/** + * @brief Class representing a pair of UTF-8 strings. + * + * This class provides functionality to work with pairs of UTF-8 strings, including conversion to byte vector and string representation. + */ class UTF8StringPair : public TypeInterface { public: + /** + * @brief Default constructor. + */ UTF8StringPair(); + + /** + * @brief Constructor that initializes the UTF-8 string pair from a byte vector. + * + * @param data_begin Iterator pointing to the start of the byte vector containing the UTF-8 string pair data. + */ UTF8StringPair(const std::vector::const_iterator &data_begin); + + /** + * @brief Virtual destructor. + */ ~UTF8StringPair() = default; friend std::ostream &operator<<(std::ostream &os, const UTF8StringPair &value); + /** + * @brief Get the size of the UTF-8 string pair. + * + * @return The total character count of the UTF-8 string pair. + */ uint16_t size() const final { return key.size() + value.size(); }; + + /** + * @brief Convert the UTF-8 string pair to a string representation. + * + * @return A string representing the UTF-8 string pair. + */ std::string as_string() const final { return key.as_string() + "=" + value.as_string(); }; + + /** + * @brief Convert the UTF-8 string pair to a byte vector. + * + * @return A byte vector representing the UTF-8 string pair. + */ std::vector as_bytes() const final; + /** + * @brief Get the key of the UTF-8 string pair. + * + * @return The key of the UTF-8 string pair. + */ inline const UTF8String get_key() const { return this->key; }; + + /** + * @brief Get the value of the UTF-8 string pair. + * + * @return The value of the UTF-8 string pair. + */ inline const UTF8String get_value() const { return this->value; }; private: - utf8_str key, value; + UTF8String key; /**< The key of the UTF-8 string pair. */ + UTF8String value; /**< The value of the UTF-8 string pair. */ }; #endif // INCLUDE_TYPES_UTF8_STRING_PAIR_HPP_ diff --git a/src/libmqttd/types/variable_byte_int.hpp b/src/libmqttd/types/variable_byte_int.hpp index 6a35685..9c0500c 100644 --- a/src/libmqttd/types/variable_byte_int.hpp +++ b/src/libmqttd/types/variable_byte_int.hpp @@ -1,19 +1,20 @@ #ifndef INCLUDE_TYPES_VARIABLE_BYTE_INT_HPP_ #define INCLUDE_TYPES_VARIABLE_BYTE_INT_HPP_ +#include #include #include #include #include -#include #include /** * @brief Class representing a Variable Byte Integer according to MQTT v5 section 1.5.5. - * + * * This class provides functionality to handle Variable Byte Integers as defined in the MQTT v5 specification. - * - * For more details, refer to: MQTT v5.0 specification, section 1.5.5. + * + * For more details + * @see file:///files/breno/mqttd/docs/mqtt_spec/MQTT%20Version%205.0.html#_Toc3901011 */ class VariableByteInteger : public TypeInterface { public: @@ -24,14 +25,14 @@ public: /** * @brief Creates a new Variable Byte Integer object from an integral integer value. - * + * * @param decoded_value The integral value to initialize the Variable Byte Integer with. */ VariableByteInteger(const uint32_t &decoded_value); /** * @brief Creates a new Variable Byte Integer object from a byte vector representing an encoded Variable Byte Integer. - * + * * @param encoded_value The byte vector representing the encoded Variable Byte Integer. * The vector must have at least 4 bytes, further bytes will be ignored. */ @@ -39,7 +40,7 @@ public: /** * @brief Creates a new Variable Byte Integer object from a byte vector iterator pointing to the beginning of the data representing an encoded Variable Byte Integer. - * + * * @param encoded_value_start The iterator pointing to the beginning of the data representing the encoded Variable Byte Integer. * The vector must have at least 4 bytes, further bytes will be ignored. */ @@ -49,28 +50,28 @@ public: /** * @brief Gets the size of the Variable Byte Integer in bytes. - * + * * @return The size of the Variable Byte Integer in bytes. */ uint16_t size() const final { return this->bytes_count; }; /** * @brief Gets the decoded value of the Variable Byte Integer as a string. - * + * * @return The decoded value of the Variable Byte Integer as a string. */ std::string as_string() const final { return std::to_string(this->decoded_value); }; /** * @brief Gets the byte array representing the encoded value of a Variable Byte Integer. - * + * * @return The byte array representing the encoded value of a Variable Byte Integer. */ std::vector as_bytes() const final { return this->encoded_value; }; /** * @brief Overloads the assignment operator for integral types. - * + * * Enables assignment of a Variable Byte Integer from an integer. */ template typename std::enable_if::value, VariableByteInteger &>::type operator=(T &); @@ -79,28 +80,28 @@ public: * @brief Overloads the output stream operator to print a Variable Byte Integer as its decoded value. */ friend std::ostream &operator<<(std::ostream &, const VariableByteInteger &); - + /** * @brief Conversion operator to uint32_t. - * + * * @return The value of the Variable Byte Integer as a uint32_t. */ inline operator uint32_t() const { return this->decoded_value; }; - + /** * @brief Gets the maximum value allowed for a Variable Byte Integer. - * + * * @return The maximum value allowed for a Variable Byte Integer. */ inline uint32_t max() const { return 268435455; }; private: - std::vector encoded_value; /**< The value of the Variable Byte integer. */ + std::vector encoded_value; /**< The value of the Variable Byte integer. */ std::vector encode(const unsigned int &); /**< Encodes an integral type to a byte vector representing a Variable Byte Integer. */ - uint32_t decoded_value; /**< The value of the Variable Byte Integer as an integer. */ + uint32_t decoded_value; /**< The value of the Variable Byte Integer as an integer. */ uint32_t decode(const std::vector &); /**< Decodes a byte vector to an integer. */ - uint8_t bytes_count; /**< How many bytes the #encoded_value has. */ + uint8_t bytes_count; /**< How many bytes the #encoded_value has. */ }; using int_vb = VariableByteInteger; diff --git a/src/libmqttd/utilities/bit.hpp b/src/libmqttd/utilities/bit.hpp index 8c9f492..bfd331b 100644 --- a/src/libmqttd/utilities/bit.hpp +++ b/src/libmqttd/utilities/bit.hpp @@ -3,15 +3,35 @@ namespace utilities { namespace bit { -template T set(T num, int position) { + +/** + * @brief Set a bit at a specified position in a value. + * + * @tparam T The type of the value. + * @param value The value to set the bit in. + * @param position The position of the bit to set. + * @return The value with the specified bit set. + */ +template +T set(T value, int position) { T mask = static_cast(1) << position; - return num | mask; + return value | mask; } -template bool get(T num, int position) { +/** + * @brief Get the value of a bit at a specified position. + * + * @tparam T The type of the value. + * @param value The value to get the bit from. + * @param position The position of the bit to get. + * @return True if the bit at the specified position is set, false otherwise. + */ +template +bool get(T value, int position) { T mask = static_cast(1) << position; - return (num & mask) != 0; + return (value & mask) != 0; } + } // namespace bit } // namespace utilities diff --git a/src/libmqttd/utilities/bytes.cpp b/src/libmqttd/utilities/bytes.cpp index 2d2dc2d..42e8bc9 100644 --- a/src/libmqttd/utilities/bytes.cpp +++ b/src/libmqttd/utilities/bytes.cpp @@ -1,13 +1,16 @@ -#include #include +#include namespace utilities { namespace bytes { + std::vector to_bytes(const std::string &value) { std::vector bytes; bytes.reserve(value.size()); std::transform(std::begin(value), std::end(value), std::back_inserter(bytes), [](char c) { return std::byte(c); }); return bytes; } + + } // namespace bytes } // namespace utilities diff --git a/src/libmqttd/utilities/bytes.hpp b/src/libmqttd/utilities/bytes.hpp index cb2fe5b..3ed2e22 100644 --- a/src/libmqttd/utilities/bytes.hpp +++ b/src/libmqttd/utilities/bytes.hpp @@ -7,12 +7,27 @@ namespace utilities { namespace bytes { +/** + * @brief Convert a string to a vector of bytes. + * + * @param value The string to convert. + * @return A vector containing the bytes of the string. + */ std::vector to_bytes(const std::string &value); -template std::vector to_bytes(const T &value) { +/** + * @brief Convert a value to a vector of bytes. + * + * @tparam T The type of the value. + * @param value The value to convert. + * @return A vector containing the bytes of the value. + */ +template +std::vector to_bytes(const T &value) { const std::byte *byte_ptr = reinterpret_cast(&value); return std::vector(byte_ptr, byte_ptr + sizeof(T)); } + } // namespace bytes } // namespace utilities diff --git a/src/libmqttd/utilities/types.hpp b/src/libmqttd/utilities/types.hpp index 6aae056..b80f5e4 100644 --- a/src/libmqttd/utilities/types.hpp +++ b/src/libmqttd/utilities/types.hpp @@ -7,7 +7,16 @@ namespace utilities { namespace types { -template typename std::enable_if::value, T>::type get_fixed_size_integer(const std::vector::const_iterator &it) { + +/** + * @brief Extracts a fixed-size integer value from a byte vector. + * + * @tparam T The type of the integer. + * @param it Iterator pointing to the beginning of the integer bytes in the vector. + * @return The extracted integer value. + */ +template +typename std::enable_if::value, T>::type get_fixed_size_integer(const std::vector::const_iterator &it) { T value = 0; for (unsigned int i = 0; i < sizeof(T); i++) { uint8_t byte_value = std::to_integer(*(std::next(it, i))); @@ -15,6 +24,7 @@ template typename std::enable_if::value, T>::ty } return value; } + } // namespace types } // namespace utilities diff --git a/src/mqttd.cpp b/src/mqttd.cpp index 59a9c0d..28b2b30 100644 --- a/src/mqttd.cpp +++ b/src/mqttd.cpp @@ -1,29 +1,67 @@ +#include "version.hpp" +#include +#include #include #include - -#include "version.hpp" -#include -#include #include +#include ConnectionListener clistener; +struct pipe_t { + union { + struct { + int read_end; + int write_end; + }; + int data[2]; + }; +}; +static_assert(sizeof(pipe_t) == 2 * sizeof(int), "Unexpected struct packing"); + +void send_trace(cpptrace::frame_ptr *buffer, std::size_t size) { + pipe_t input_pipe; + pipe(input_pipe.data); + const pid_t pid = fork(); + if (pid == -1) + return; + if (pid == 0) { // child + dup2(input_pipe.read_end, STDIN_FILENO); + close(input_pipe.read_end); + close(input_pipe.write_end); + execl("mqttd_stacktracer", "mqttd_stacktracer", nullptr); + _exit(1); + } + + for (std::size_t i = 0; i < size; i++) { + cpptrace::safe_object_frame frame; + cpptrace::get_safe_object_frame(buffer[i], &frame); + write(input_pipe.write_end, &frame, sizeof(frame)); + } + close(input_pipe.read_end); + close(input_pipe.write_end); + waitpid(pid, nullptr, 0); +} + void termination_handler(int signal_num) { spdlog::info("Received signal " + std::string(strsignal(signal_num))); - std::set backtrace_signals = {SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGABRT}; + std::set backtrace_signals = {SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGABRT, SIGTRAP}; auto is_backtrace_signal = backtrace_signals.find(signal_num); if (is_backtrace_signal != backtrace_signals.end()) { - backtrace::backtrace(); - exit(ExitCode::ERROR); + constexpr std::size_t SIZE = 256; + cpptrace::frame_ptr buffer[SIZE]; + std::size_t count = cpptrace::safe_generate_raw_trace(buffer, SIZE); + send_trace(buffer, count); + _exit(ExitCode::ERROR); } - + clistener.stop(); exit(ExitCode::SUCCESS); } void set_signal_handlers() { - std::set termination_signals = {SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSYS, SIGABRT, SIGHUP, SIGINT, SIGQUIT, SIGTERM}; + std::set termination_signals = {SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSYS, SIGABRT, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGTRAP}; // Blocking signals with set sigset_t block_mask; @@ -43,9 +81,21 @@ void set_signal_handlers() { } } +void warmup_cpptrace() { + cpptrace::frame_ptr buffer[10]; + cpptrace::safe_generate_raw_trace(buffer, 10); + cpptrace::safe_object_frame frame; + cpptrace::get_safe_object_frame(buffer[0], &frame); +} + int main() { std::cout << "MQTTd Version " << MQTTD_VERSION_MAJOR << "." << MQTTD_VERSION_MINOR << "." << MQTTD_VERSION_PATCH << std::endl; + cpptrace::absorb_trace_exceptions(false); + cpptrace::register_terminate_handler(); + cpptrace::enable_inlined_call_resolution(true); + warmup_cpptrace(); set_signal_handlers(); + raise(SIGSEGV); // spdlog::set_level(spdlog::level::debug); diff --git a/src/mqttd_stacktracer.cpp b/src/mqttd_stacktracer.cpp new file mode 100644 index 0000000..eb18248 --- /dev/null +++ b/src/mqttd_stacktracer.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +int main() { + cpptrace::object_trace trace; + while (true) { + cpptrace::safe_object_frame frame; + std::size_t res = fread(&frame, sizeof(frame), 1, stdin); + if (res == 0) + break; + else if (res == 1){ + trace.frames.push_back(frame.resolve()); + } + else { + std::cerr << "Oops, size mismatch " << res << " " << sizeof(frame) << std::endl; + break; + } + } + trace.resolve().print(); +} diff --git a/src/version.hpp b/src/version.hpp index 877d8a4..4103854 100644 --- a/src/version.hpp +++ b/src/version.hpp @@ -1,5 +1,5 @@ #define MQTTD_VERSION_MAJOR 0 #define MQTTD_VERSION_MINOR 0 #define MQTTD_VERSION_PATCH 1 -#define MQTTD_COMMIT_HASH f91fe172be4c51f393bdd4184e62281d75eac64e -#define MQTTD_BUILD_TIMESTAMP 1707947036 +#define MQTTD_COMMIT_HASH ccd31f1802fa0052819a18599c9932e1c74e8a1a +#define MQTTD_BUILD_TIMESTAMP 1713729654